I'm trying to create my own custom folder tree model using QStandardItemModel. I succeeded in making it using TreeWidget, but the correct address was not printed, so I used the QStandardItemModel where the index is stored.
However, I'm leaving a question because I'm stuck in many ways and I want to get some advice on this.
void QtWidgetsApplication1::AddDocTree(QStandardItem *DocItem, QString Path)
{
QString path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
QDir* rootDir = new QDir(path);
QFileInfoList filesList = rootDir->entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
DocItem = TestModel->invisibleRootItem();
foreach(QFileInfo fileInfo, filesList)
{
if (fileInfo.isFile())
{
QIcon BasicIcon = mpIconProvider->icon(fileInfo);
child = new QStandardItem(BasicIcon, fileInfo.fileName());
child->setAccessibleDescription(fileInfo.filePath());
}
else
{
QIcon BasicIcon = mpIconProvider->icon(fileInfo);
child = new QStandardItem(BasicIcon, fileInfo.fileName());
child->setAccessibleDescription(fileInfo.filePath());
}
DocItem->appendRow(child);
AddDocTree(child, fileInfo.filePath());
DocItem = child;
}
}
I have a drive model that we've already created using the QFilesystemModel, but ultimately we have to create a folder tree that looks like a Windows File Explorer.
Related
The TreeModel creation of the drive was successful using TreeWidget. However, when I clicked on a folder, the children of that folder kept being created, and I tried many times to prevent it, but it kept failing.
connect(ui->treeWidget, &QTreeWidget::itemClicked, this, &QtWidgetsApplication1::Addtree);
void QtWidgetsApplication1::Addtree(QTreeWidgetItem *root4, int column)
{
QDir* rootDir = new QDir(root4->text(2));
QDir test(root4->text(2));
QFileInfoList filesList = rootDir->entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
foreach(QFileInfo fileInfo, filesList)
{
QTreeWidgetItem* child = new QTreeWidgetItem();
child->setText(0, fileInfo.fileName());
if (fileInfo.isDir())
{
QIcon BasicIcon = mpIconProvider->icon(fileInfo);
child->setIcon(0, BasicIcon);
child->setText(2, fileInfo.filePath());
//child->setCheckState(1, Qt::Checked);
}
root4->addChild(child);
ui->treeWidget->addTopLevelItem(root4);
}
}
The code associated with itemClicked to create a child folder is as follows, and I'm not sure how to add it here to limit it to create it once.
To make it clear, I'm creating a treeview that will instantiate itself after the user creates a folder and said folder will be added as treeitem.
I currently have this:
TreeView treeView = new TreeView();
// Create new folder
MenuItem menuItem1 = new MenuItem("Create New Folder");
menuItem1.setOnAction(e -> {
System.out.println("Please name your directory:");
Scanner in = new Scanner(System.in);
String strFolder = in. nextLine();
createFolder(strFolder); // Create folder
TreeItem rootFolder = new TreeItem(strFolder); // Create new TreeItem
treeView.setRoot(rootFolder); // Replace old folder with new one
// rootFolder.getChildren().add(rootFolder);
// rootItem.getChildren().add(rootFolder);
});
After the treeView, I declared a new Menu Item that which will trigger an event after being clicked on.
The event will ask the user for a name to use as the root folder for the treeView. Now thats working fine.
Now what I'm having troubles with, is how to create more folders inside the root folder created and display them as subfolders in the treeView?
So far my code only does replace the old root folder by the new one created. Instead of setting the root folder again, how can i make it so it just adds those folders inside the first one and display them - again - in the treeView as subfolders?
Did I explain myself?
Thanks.
Simply add TreeItem(s) to the child list of the TreeItem. The following example replaces the root, if no items are selected and otherwise adds the new item as a child of the selected one:
TreeView<String> treeView = new TreeView<>(); // never use raw type without good reason
// Create new folder
MenuItem menuItem1 = new MenuItem("Create New Folder");
menuItem1.setOnAction(e -> {
TextInputDialog dialog = new TextInputDialog(); // replacing console input with dialog here
dialog.setHeaderText("Please name your directory:");
String strFolder = dialog.showAndWait().orElse(null);
if (strFolder != null) {
TreeItem<String> newFolder = new TreeItem<>(strFolder); // Create new TreeItem
TreeItem<String> selection = treeView.getSelectionModel().getSelectedItem();
createFolder(strFolder); // Create folder ; TODO: make dependent on parent???
if (selection == null) {
treeView.setRoot(newFolder); // Replace old folder with new one
} else {
selection.getChildren().add(newFolder);
selection.setExpanded(true); // make sure we're able to see the new child
}
}
});
I'm trying to create my first extension for visual studio and so far I've been following this tutorial to get me started (http://www.diaryofaninja.com/blog/2014/02/18/who-said-building-visual-studio-extensions-was-hard).
Now I have a custom menu item appearing when I click on a file in the solution explorer.
What I need now for my small project is to get the path of the file selected in the solution explorer but I can't understand how can I do that.
Any help?
---------------------------- EDIT ------------------------------
As matze said, the answer is in the link I posted. I just didn't notice it when I wrote it.
In the meanwhile I also found another possible answer in this thread: How to get the details of the selected item in solution explorer using vs package
where I found this code:
foreach (UIHierarchyItem selItem in selectedItems)
{
ProjectItem prjItem = selItem.Object as ProjectItem;
string filePath = prjItem.Properties.Item("FullPath").Value.ToString();
//System.Windows.Forms.MessageBox.Show(selItem.Name + filePath);
return filePath;
}
So, here are two ways to get the path to the selected file(s) :)
For future reference:
//In your async method load the DTE
var dte2 = await ServiceProvider.GetGlobalServiceAsync(typeof(SDTE)) as DTE2;
var selectedItems = dte2.SelectItems;
if(selectedItems.MultiSelect || selectedItems.Count > 1){ //Use either/or
for(short i = 1; i <= selectedItems.Count; i++){
//Get selected item
var selectedItem = selectedItems[i];
//Get associated project item (selectedItem.ProjectItem
//If selectedItem is a project, then selectedItem.ProjectItem will be null,
//and selectedItem.Project will not be null.
var projectItem = selectedItem.ProjectItem;
//Get project for ProjectItem
var project = projectItem.ContainingProject;
// Or get project object if selectedItem is a project
var sproject = selectedItem.Project;
//Is selectedItem a physical folder?
var isFolder = projectItem.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder;
//Else, get item's folder
var itemFolder = new FileInfo(projectItem.Properties.Item("FullPath").ToString()).Directory;
//Find config file
var configFiles itemFolder.GetFiles("web.config");
var configfile = configFiles.length > 0 ? configFiles[0] : null;
//Turn config file into ProjectItem object
var configItem = dte2.solution.FindProjectItem(configFile.FullName);
}
}
I hope someone finds this helpful...
The article you mentioned already contains a solution for that.
Look for the menuCommand_BeforeQueryStatus method in the sample code. It uses the IsSingleProjectItemSelection method to obtain an IVsHierarchy object representing the project as well as the id of the selected item. It seems that you can safely cast the hierarchy to IVsProject and use it´s GetMkDocument function to query the item´s fullpath...
IVsHierarchy hierarchy = null;
uint itemid = VSConstants.VSITEMID_NIL;
if (IsSingleProjectItemSelection(out hierarchy, out itemid))
{
IVsProject project;
if ((project = hierarchy as IVsProject) != null)
{
string itemFullPath = null;
project.GetMkDocument(itemid, out itemFullPath);
}
}
I don´t want to copy the entire code from the article into this answer, but it might be of interest how the IsSingleProjectItemSelection function obtains the selected item; so I just add some notes instead which may guide into the right direction... The method uses the GetCurrentSelection method of the global IVsMonitorSelection service to query to the current selected item.
I'm new to Qt (previous experience is mostly Java) and am trying to find a good way of creating child directories and files given a QDir parent (and hold onto/create the QDir for the new child).
I've come up with a method to do this (I think!), but was unsure if this is the right way, or if there is already something built in that would do this for me.
Hope you can help.
QDir* MyClass::createChildDir(QDir* parent, QString dirName)
{
parent->mkdir(dirName);
QString newPath = parent->filePath(dirName);
QDir* newDir = new QDir(newPath);
return newDir;
}
I am working on Tridon 2009 using .NET Templating C# 2.0
I need to read all the components from folders and its subfolder.
If in my code I write:
OrganizationalItem imageFolder =
(OrganizationalItem)m_Engine.GetObject(comp.OrganizationalItem.Id);
I am able to read all the components in subfolder from the place where indicator component is present, but I am not able to read other components present in the folder where indicator is present.
But If I write
OrganizationalItem imageFolder = (OrganizationalItem)m_Engine.GetObject(
comp.OrganizationalItem.OrganizationalItem.Id);
then I am able to read only folder where indicator component is present.
Below is my code.
XmlDocument doc = xBase.createNewXmlDocRoot("ImageLibrary");
XmlElement root = doc.DocumentElement;
Filter filter = new Filter();
Component comp = this.GetComponent();
filter.Conditions["ItemType"] = ItemType.Folder;
filter.Conditions["Recursive"] = "true";
OrganizationalItem imageFolder =
(OrganizationalItem)m_Engine.GetObject(comp.OrganizationalItem.Id);
XmlElement itemList = imageFolder.GetListItems(filter);
foreach (XmlElement itemImg in itemList)
{
filter.Conditions["ItemType"] = ItemType.Component;
filter.Conditions["BasedOnSchema"] = comp.Schema.Id;
OrganizationalItem imgFolder =
(OrganizationalItem)m_Engine.GetObject(itemImg.GetAttribute("ID")
.ToString());
XmlElement imageLibs = imgFolder.GetListItems(filter);
doc = this.createImageNodes(imageLibs, doc, filter, comp);
foreach (XmlElement imglib in imageLibsList)
{
XmlElement imageroot = doc.CreateElement("Image");
XmlElement uploadeddateNode = doc.CreateElement("DateUploaded");
Component imgComp =
(Component)m_Engine.GetObject(imglib.GetAttribute("ID"));
}
}
Please suggest.
I see a lot of superfluous code on your snippet regarding the question "Reading all components from folder and subfolder"
But answering the question itself, when you are doing:
OrganizationalItem imageFolder = (OrganizationalItem)m_Engine.GetObject(comp.OrganizationalItem.Id);
Your are not being able to read components present on that folder, because you have previously set the filter to folders only on the following line:
filter.Conditions["ItemType"] = ItemType.Folder;
Solution:
If you want to retrieve all components on the "indicator component" folder and below, you need to set the filter on your first search as following:
filter.Conditions["Recursive"] = "true";
filter.Conditions["ItemType"] = ItemType.Component;
filter.Conditions["BasedOnSchema"] = comp.Schema.Id;
And perform the search:
OrganizationalItem imageFolder = (OrganizationalItem)m_Engine.GetObject(comp.OrganizationalItem.Id);
XmlElement itemList = imageFolder.GetListItems(filter);
Pretty basic stuff. Try to avoid using Filter class, since it was deprecated in 2009, and use GetListItems as much as possible as fetching lists is ALWAYS faster.
public class GetComponentsInSameFolder : ITemplate
{
public void Transform(Engine engine, Package package)
{
TemplatingLogger log = TemplatingLogger.GetLogger(GetType());
if (package.GetByName(Package.ComponentName) == null)
{
log.Info("This template should only be used with Component Templates. Could not find component in package, exiting");
return;
}
var c = (Component)engine.GetObject(package.GetByName(Package.ComponentName));
var container = (Folder)c.OrganizationalItem;
var filter = new OrganizationalItemItemsFilter(engine.GetSession()) { ItemTypes = new[] { ItemType.Component } };
// Always faster to use GetListItems if we only need limited elements
foreach (XmlNode node in container.GetListItems(filter))
{
string componentId = node.Attributes["ID"].Value;
string componentTitle = node.Attributes["Title"].Value;
}
// If we need more info, use GetItems instead
foreach (Component component in container.GetItems(filter))
{
// If your filter is messed up, GetItems will return objects that may
// not be a Component, in which case the code will blow up with an
// InvalidCastException. Be careful with filter.ItemTypes[]
Schema componentSchema = component.Schema;
SchemaPurpose purpose = componentSchema.Purpose;
XmlElement content = component.Content;
}
}
}
I'd think you'd want to collect sub folders and recursively call your function for each of them, which seems like what you're trying to achieve.
Is this function called createImageNodes() and where do you set imageLibsList?
It looks like you're treating each item as a folder in your first loop, what about the components?