I'm trying to make some kind of recursion. If you open P then you can open P again or do something else. And here is my problem:
I can't add same item twice.
while (*it) {
if ((*it)->text(0) == item->text(0)){
(*it)->setText(0,"Add_item");
(*it)->addChild(item);
}
}
Can I make a loop in QTree ?
You need to create another item. It seems you add for the same text the same item object over and over again as child. So making a copy of the item and adding that copy as child should work.
Related
I would like to create a organogram like:
https://codepen.io/bernardoantunes/pen/inrbh using 2sic Content.
I would like to create a content-type 'organogram' with the following fields:
Title as String
Parent as Entity (of type Organogram)
Description as String
Link as Hyperlink
Using this content-type i would add some elements where child elements could be created.
for example:
- Root
- Child 1 (Root is selected in the Parent field)
- Child 2 (Root is selected in the Parent field)
- Child 3 (Child 2 is selected in the Parent field)
Could this be done using 2sic content App?
I created the content-type and added some elements. Created a razor template and then it gives an error.
operator '==' can not be applied to operands of type System.Collections.Generic.List and ToSic.SexyContent.DynamicEntity
Razor template:
#using Connect.Koi;
#{
var first = AsDynamic(Data["Default"]).First();
var all = AsDynamic(Data["Default"]);
}
<div>#first.Title</div>
var children = all.Where(x => x.parent == first).ToList();
<div>#children.Count</div>
Basically the AsDynamic(...) creates wrapped entity-objects, whereas ...parent gives you a list of related items (because it could have more than 1 parent). If this is the code you want to use, I suggest 1 things.
On the .parent (which should probably be .Parent) use the [0] or .FirstOrDefault() so it's .Parent.FirstOrDefault() == first - remember to enable LINQ by #using System.Linq
Don't compare the AsDynamic objects, because they will be different objects. Better compare the id using .EntityId or something.
So you're resulting compare will probably be .Parent[0].EntityId == first.EntityId.
What I don't like about your solution is the idea, that the first item in the Default-list will somehow be the important one. This doesn't feel right, but I don't know your whole solution...
I need to delete a qlistwidget item by text content
I tried:
QString mstring = "Programmer II";
QList<QListWidgetItem *> items = ui->listJobs->findItems(mstring, Qt::MatchExactly);
if (items.size() > 0)
ui->listJobs->takeItem( ui->listJobs->currentRow() );
...and various permutations, but I'm missing something. The code above compiles, but does not delete the item from the qlistwidget.
The code doesn't indicate what the value of currentRow is, but findItems doesn't set it, so it's unlikely to correlate with the value you're trying to remove. I don't see any way to use the results of findItems and get the row(s) you want to remove. I think you have to loop through the contents, compare the text of each item, and then remove the ones that match. You'll probably want to do the loop in reverse order; otherwise, once you've removed an item, the loop counter will no longer match the list item's row numbers.
I have a custom Sitecore command that I would like to expand upon to determine if the current item has a parent item matching a certain template id.
When the command/button is clicked, I will have access to the current Item.
My initial attempt, since I had issues with escaping the FullPath for use in a query, was to loop through the parent item (and then that item's parent, etcetera) to determine if any matched the template.
However, there seems like there should be a better way to do this.
So given an item, what's the best way to find whether it has a parent item that is of a certain template?
SXA way
public static Item GetParentOfTemplate(this Item item, ID templateId)
{
if (item == null)
{
return null;
}
ItemRelationCacheValue itemRelationCacheValue = ParentOfTemplateCache.GetCacheForDatabase(item.Database.Name)?.Get(item, templateId);
if (itemRelationCacheValue != null)
{
return item.Database.GetItem(itemRelationCacheValue.OutputID);
}
Template template = TemplateManager.GetTemplate(templateId, item.Database);
if (template == null)
{
return null;
}
ID iD = item.ID;
while (item != null)
{
Template template2 = TemplateManager.GetTemplate(item);
if (template2 != null && template2.DescendsFromOrEquals(template.ID))
{
ItemRelationCacheValue value = new ItemRelationCacheValue(iD, item.Database.Name, templateId, item.ID);
ParentOfTemplateCache.GetCacheForDatabase(item.Database.Name)?.Set(value);
return item;
}
item = item.Parent;
}
return null;
}
There's not really a good way to do it. In a regular system you'd do it in SQL, but Sitecore has obfuscated their 'Nexus' code which I believe is where all of this data access/mapping logic happens thus I don't really know how that part of Sitecore works so it's a difficult to try to reverse engineer a query to do this efficiently.
What I use in my projects I use a recursive function like this.
I use a delegate to determine if the item is a match for what I'm looking for, and just recurse up the tree - dropping out to return null if it reaches the root node.
public delegate bool ItemSelectionCondition(Item sitecoreItem);
public static Item GetAncestor(Item sitecoreItem, ItemSelectionCondition selectionCondition)
{
Item parent = sitecoreItem.Parent;
if (selectionCondition(parent))
{
return parent;
}
else if (Sitecore.ItemIDs.RootID == parent.ID)
{
return null;
}
else
{
return GetAncestor(parent, selectionCondition);
}
}
So to work with this you'd need to define a delgate something like:
public static bool IsTemplateX(Item item)
{
return item.TemplateID == Constants.TemplateXId;
}
It's quite a simple solution that's flexible enough to work with any Ancestor or Parent type things that I've needed to do.
Be warned though it will take several seconds to run the first time if Sitecore hasn't cached all of the items it needs to look at, but subsequent times it will take a bearable amount of time.
EDIT: Since this answer has gotten a few downvotes I thought I'd explain why it's the best way to do this in Sitecore.
The reson why a recursive approach is better that iterative is two-fold. First, it's less code so it looks nicer - but if that's not enough the second reason is that if you're careful about how you've structured your code and are compiling your project you'll be able to take advantage of tail recursion.
The reason why using Item.Axes.Ancestors (Or Item.Axes.GetAncestors() in later versions of Sitecore) is bad is because it has five steps:
Allocate a List of Items
Iteratively add All Ancestors to that list
Reverse the order of the List
Convert the list to an array
Use Linq to filter the array
This means that you're doing twice as much allocation as if you were to just recurse to the top of the content tree, but you're also ruling out the possibility of exiting the recursion at the first relevant item - and avoiding unecessary calls to the database.
I do have to conceed that the comment about using a Lucene Index however is right - that's the way that is potentially the fastest in almost all scenarios just because it can reduce your time finding the item down to a single Sitecore Query - or no Sitecore Query if you index the data about that ancestor that you need.
If I want to change the focus item in the ListView control I do the following:
BOOL setListFocusItem(CListCtrl* pList, int nIndex)
{
return !!pList->SetItemState(nInd, LVIS_FOCUSED, LVIS_FOCUSED);
}
Is this the way you do it?
Because the focus itself changes but there's one issue that this creates. For instance, if the list had 100 items and the focus was on item 1. If I then call my method as such setListFocusItem(99); the focus changes to item 99, but then if I shift-click on item 90, I would expect the list to have items 90 through 99 to be selected. But instead the list selects items 1 through 90. So obviously my setListFocusItem() method does not change the shift-click "first" location. So question is how to make it do it?
Short answer : use the LVM_SETSELECTIONMARK message.
(In MFC-ese, CListCtrl::SetSelectionMark).
I'm trying to parse an Xml file using QDomDocument.
I've got the root element. Now I need to find and extract specfic nodes
under the root element but only at the first level of hierarchy.
I tried to use:
QDomElement root = doc.documentElement();
QDomNodeList nodeList = root.elementsByTagName("apple");
But this returns me a nodeList which contains the nodes with tag Name "apple"
in all levels of hierarchy. But I need only a first level search.
Could someone please help me out.
Thanks
There's no method to do exactly what you want but it's easy to achieve by iterating over the children with something like:
QList<QDomElement> elements;
QDomElement child = root.firstChildElement("apple");
while(!child.isNull()) {
elements.append( child );
child = child.nextSiblingElement("apple");
}