This is in reference to yesterday's question "How do I create folders in ASP.NET in code behind". The problem is that I want to create dynamic folders at run time. Folder names will be entered via a TextBox and output will be displayed in a TreeView. The form will submit if I enter the first folder name into textbox1 and click the "Add Folder" button. When I submit multiple folders with the same name, the output should be an indexed increment of the name (e.g., FooFolder, FooFolder(2), FooFolder(3), etc). There are two events: Add Folder Event and Remove Folder Event. If I select a particular child folder and click on the "Remove folder" button, the folder will be removed. For adding a folder I have written the following code:
TreeNode tnode = new TreeNode();
if (TreeView1.Nodes.Count > 0)
{
int found = 0;
for (int i = 0; i < TreeView1.Nodes.Count; i++)
{
if (TreeView1.Nodes[i].Text == TextBox1.Text)
found += 1+i;
}
if (found > 0)
{
tnode.Text = TextBox1.Text + found.ToString();
}
else
{
tnode.Text = TextBox1.Text;
}
}
else
{
tnode.Text = TextBox1.Text;
}
TreeView1.Nodes.Add(tnode);
}
In my code, the ChildNode index is not incrementing; it is always 1, like this:
Sumit
Sumit(1)
Sumit(1)
Sumit(1)
Amit
Amit(5)
Amit(5)
Amit(5)
In the treeview, I have set ImageSet="XPFileExplorer". So the output should look like this:
-Root
-Sumit(Parent1)
NewFolder
NewFolder(2)
NewFolder(3)
NewFolder(4)
NewFolder(5)
-Amit(Parent2)
FooFolder
FooFolder(2)
FooFolder(3)
FooFolder(4)
FooFolder(5)
If I delete any child folder, say, Newfolder(3) and Newfolder(4) and create these same folders under the same Sumit(Parent1), the index should be Newfolder(3),Newfolder(4). If I create one more NewFolder under Sumit with same name then the index should be NewFolder(6).
Could somebody please modify my code to get this desired output?
Your issue here is your algorithim to detect if the item exists. Basically your code:
for (int i = 0; i < TreeView1.Nodes.Count; i++)
{
if (TreeView1.Nodes[i].Text == TextBox1.Text)
found += 1+i;
}
if (found > 0)
{
tnode.Text = TextBox1.Text + found.ToString();
}
else
{
tnode.Text = TextBox1.Text;
}
Let's walk through this. The user submits NewFolder your code goes through and doesn't find any node called NewFolder, so it sets the node to NewFolder.
Now the user clicks add again for NewFolder, this time it finds NewFolder so the new name becomes NewFolder1.
Now the user clicks add again for NewFolder, this time it finds NewFolder so the new name becomes NewFolder1.
Your comparing if TreeView1.Nodes[i].Text == TextBox1.Text, which only one node will ever have this name. You will need to strip off the numeric portion of the name.
If your using a naming convention like NewFolder(1) then you can easily do this. But based on the code you have there the name of the node would be NewFolder1
Before you do this, I learned the hard way that you should not create/remove folders under a running application, or you will cause your app pool to recycle. So make sure that you are creating directories somewhere else on the server. (Hopefully you have that access)
Your text comparison is off. Since you may have added numbers to previous nodes under the same parent, you will only encounter the new name once.
It should look like:
if (TreeView1.Nodes[i].Text.StartsWith(TextBox1.Text))
found++
Related
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 have a form, when i click on my button.It adds to my table A (what my factbox shows)is it possible to refresh the factbox with X++ code? I can't figure out how to refresh my infopart or query which factbox uses.
For an infopart you can call an update of the data source of the infopart's form run:
void clicked()
{
PartList partList;
int i;
FormRun infoPartFormRun;
FormDataSource infoPartDataSource;
super();
partList = new PartList(element);
for (i = 1; i <= partList.partCount(); i++)
{
infoPartFormRun = partList.getPartById(i);
if (infoPartFormRun.name() == identifierStr(MyInfoPart))
{
infoPartDataSource = infoPartFormRun.dataSource();
if (infoPartDataSource)
{
infoPartDataSource.research();
}
}
}
}
I added the check for the infoPartDataSource because I first tested this with a cue group fact box, which does not have a data source (or at least I could not figure out how to get the data source of one of the cues in the cue group and since you asked for an infopart fact box, I did not investigate further).
Update: The issue seems to be popular at the moment, Martin Dráb also wrote in his blog about it: Refreshing form parts
I have an application, in which I have added a QTabWidget.
Tabs are closable.
When I add new tab, if the tab is already added, it still add new tab and make duplicate.
I want to avoid this duplication.
If the tab is opened already then It just active that tab and not open again.
You help will be appreciated.
Thanks
To add on top of Prakash's answer, be aware that some times the tab title is not a good identifier of the content of the tab (this of course depends on the situation). For example, you might have a file manager where the current directory is the title of the tab, but there might be different directories with the same name across your filesystem.
I would follow the following strategy for identifying tab contents: Qt allows you to set dynamical properties to widgets (see QObject::setProperty), so each time you create a new tab, for example of a file manager, you might do something like
widget = ...
widget->setProperty("tab_dir_fullpath", the_full_path);
tabWidget->addWidget(widget, directory_name);
where the_full_path would be a unique identifier (in this example, the full absolute path to the current directory), which will not be displayed to the user but which you can later use to see if a given directory is already open.
Then, when opening a new tab, you should check whether the same full path is already open:
for (int k = 0; k < tabWidget->count(); ++k) {
if (tabWidget->widget(k)->property("tab_dir_fullpath").toString() == the_full_path_to_open) {
tabWidget->setCurrentIndex(k);
return;
}
}
... // open new tab, as in the previous snippet.
Use tabText(int index) to get the identifier of the each tab before adding a new tab addTab(QWidget * page, const QString & label) and compare the label texts, if already exist just setCurrentIndex of that index or else add a new tab.
Inspired by Noor Nawaz's comment, my approch is:
void MainWindow::openPanel1()
{
for(int i=0;i<ui->tabWidget->count();i++) {
if(ui->tabWidget->tabText(i) == "Panel1") {
ui->tabWidget->setCurrentIndex(i);
return;
}
}
Panel1 = new panel1Widget();
int index = ui->tabWidget->addTab(Panel1,"Panel1");
ui->tabWidget->setCurrentIndex(index);
}
Also its very good to use setTabData() instead of property which is more proper way of doing.
I can get strings representing group and user permissions for a given folder with the following.
Code
// assumes Core Service client "client"
var folderData = client.Read("tcm:5-26-2", new ReadOptions()) as FolderData;
var accessControlEntryDataArray =
folderData.AccessControlList.AccessControlEntries;
Console.WriteLine(folderData.Title);
foreach (var accessControlEntryData in accessControlEntryDataArray)
{
Console.WriteLine("{0} has {1}",
accessControlEntryData.Trustee.Title,
accessControlEntryData.AllowedPermissions.ToString());
}
Output
Some Folder
Everyone has Read
Editor has None
Chief Editor has None
Publication Manager has None
Interaction Manager has None
T2011-CB-R2\areyes has All
[scope] Editor 020 Create has Read, Write
T2011-CB-R2\local1 has Read, Write, Delete
[rights] Author - Content has None
Seems like the four possible values for `AllowedPermissions are:
None
Read
Read, Write
Read, Write, Delete
All
This works great for my use case to create a folder permissions report. I can .Replace() these to a familiar notation (e.g. rw-- or rwdl).
But is manipulating these string values the right approach to set permissions as well? I'd imagine I'd want objects or maybe enums instead. Could someone point me in the right direction?
Also I noticed I get some, but not all non-applicable groups set as None. I don't specifically need them here, but I'm curious at what determines whether those get returned--did I miss something in my code?
Rights and Permissions are enums, indeed. You can set using the method below. If you want to set multiple rights you should do something like "Rights.Read | Rights.Write"
Keep in mind that this method will return you object that you have to save \ update \ create after
public static OrganizationalItemData SetPermissionsOnOrganizationalItem(
OrganizationalItemData organizationalItem,
TrusteeData trustee,
Permissions allowedPermissions,
Permissions deniedPermissions = Permissions.None)
{
if (organizationalItem.AccessControlList == null)
{
organizationalItem.AccessControlList
= new AccessControlListData
{AccessControlEntries = new AccessControlEntryData[0]};
}
var entries = organizationalItem.AccessControlList
.AccessControlEntries.ToList();
// First check if this trustee already has some permissions
var entry = entries.SingleOrDefault(
ace => ace.Trustee.IdRef == trustee.Id);
if (entry != null)
{
// Remove this entry
entries.Remove(entry);
}
entries.Add(new AccessControlEntryData
{
AllowedPermissions = allowedPermissions,
DeniedPermissions = deniedPermissions,
Trustee = new LinkToTrusteeData { IdRef = trustee.Id }
});
organizationalItem.AccessControlList.AccessControlEntries
= entries.ToArray();
return organizationalItem;
}
I create a menu dynamically. I add several checkable actions into one menu. Sometimes actions may have the same text that user sees. It's up to user (actually user adds commands into menu).
The problem is in this case clicking works wrong. If I click on the first action (from 2 with the same texts) everything is good but if I click on the second one, both actions are selected. I don't understand why. The code where actions have been created is here:
for (int i = 0; i< currentList.size(); i++)
{
QString lanKey = currentList.at(i)->Language->toString();
QAction* lanAction = new QAction(this);
QString name ="action_" + currentList.at(i)->Id->toString();
lanAction->setObjectName(name);
lanAction->setText(lanKey);
lanAction->setCheckable(true);
lanAction->setData(i);
connect(lanAction, SIGNAL(triggered(bool)), this, SLOT(ShowSomething(bool)));
ui->menuMy->addAction(lanAction);
}
Here, lanKey is language that may be the same for different actions. Anyway click on the specific action should lead only to checking of this action. What's wrong?
The slot is here:
void VMainWindow::ShowSomething(bool IsTriggered)
{
QAction* senderAction = (QAction*)sender();
int listIndex = senderAction->data().toInt();
if (IsTriggered)
{
CreateEditor(subtitles, listIndex);
}
else
{
//hide this editor
QString name = "editor" + editorsList->Id->toString();
QDockWidget* editorDock = this->findChild<QDockWidget*>(name);
if (editorDock != 0)
{
this->removeDockWidget(editorDock);
this->setLayout(layout());
}
}
}
Thanks
The source of problem is found: it turned out that the slot finds the checked action wrong - by text, not by id.
I can't find a logical issue in the code you posted so far. Here are a couple of options which I would try in order to resolve this problem:
Limit the users possibilities when adding items to a menu so that he can't add two items with the same name.
Add qDebug() output to ShowSomething to see if there is a problem with signals&slots. For example, if the slot gets called once for the first item but twice for the second item there is a problem there.
Debug into CreateEditor step-by-step.
As the problem seems to appear only for actions with a similar name, you should make sure that you never make a lookup of an action (or something related) by its text() but rather by its data() or objectName() (assuming that currentList.at(i)->Id will always be unique)