QModelIndexList BtTreeModel::allChildren(QModelIndex ndx) { QModelIndexList leafNodes; QList<BtTreeItem*> folders; int i; // Don't send an invalid index or something that isn't a folder if ( ! ndx.isValid() || type(ndx) != BtTreeItem::FOLDER ) return leafNodes; BtTreeItem* start = item(ndx); folders.append(start); while ( ! folders.isEmpty() ) { BtTreeItem* target = folders.takeFirst(); for (i=0; i < target->childCount(); ++i) { BtTreeItem* next = target->child(i); // If a folder, push it onto the folders stack for later processing if ( next->type() == BtTreeItem::FOLDER ) folders.append(next); else // Leafnode leafNodes.append(createIndex(i,0,next)); } } return leafNodes; }
QModelIndex BtTreeModel::createFolderTree( QStringList dirs, BtTreeItem* parent, QString pPath) { BtTreeItem* pItem = parent; // Start the loop. We are going to return ndx at the end, // so we need to declare and initialize outside of the loop QModelIndex ndx = createIndex(pItem->childCount(),0,pItem); // Need to call this because we are adding different things with different // column counts. Just using the rowsAboutToBeAdded throws ugly errors and // then a sigsegv emit layoutAboutToBeChanged(); foreach ( QString cur, dirs ) { QString fPath; BtFolder* temp = new BtFolder(); int i; // If the parent item is a folder, use its full path if ( pItem->type() == BtTreeItem::FOLDER ) fPath = pItem->folder()->fullPath() % "/" % cur; else fPath = pPath % "/" % cur; // If it isn't we need the parent path fPath.replace(QRegExp("//"), "/"); // Set the full path, which will set the name and the path temp->setfullPath(fPath); i = pItem->childCount(); pItem->insertChildren(i, 1, BtTreeItem::FOLDER); pItem->child(i)->setData(BtTreeItem::FOLDER, temp); // Insert the item into the tree. If it fails, bug out //if ( ! insertRow(i, ndx, temp, BtTreeItem::FOLDER) ) //{ // emit layoutChanged(); // return QModelIndex(); //} // Set the parent item to point to the newly created tree pItem = pItem->child(i); // And this for the return ndx = createIndex(pItem->childCount(), 0, pItem); }
bool BtTreeModel::renameFolder(BtFolder* victim, QString newName) { QModelIndex ndx = findFolder(victim->fullPath(), 0, false); QModelIndex pInd; QString targetPath = newName % "/" % victim->name(); QPair<QString,BtTreeItem*> f; QList<QPair<QString, BtTreeItem*> > folders; // This space is important ^ int i, kids,src; if ( ! ndx.isValid() ) return false; pInd = parent(ndx); if ( ! pInd.isValid() ) return false; BtTreeItem* start = item(ndx); f.first = targetPath; f.second = start; folders.append(f); while ( ! folders.isEmpty() ) { // This looks weird, but it is needed for later f = folders.takeFirst(); targetPath = f.first; BtTreeItem* target = f.second; // As we move things, childCount changes. This makes sure we loop // through all of the kids kids = target->childCount(); src = 0; // Ok. We have a start and an index. for (i=0; i < kids; ++i) { // This looks weird and it is. As we move children out, the 0 items // changes to the next child. In the case of a folder, though, we // don't move it, so we need to get the item beyond that. BtTreeItem* next = target->child(src); // If a folder, push it onto the folders stack for latter processing if ( next->type() == BtTreeItem::FOLDER ) { QPair<QString,BtTreeItem*> newTarget; newTarget.first = targetPath % "/" % next->name(); newTarget.second = next; folders.append(newTarget); src++; } else // Leafnode next->thing()->setFolder(targetPath); } } // Last thing is to remove the victim. i = start->childNumber(); return removeRows(i, 1, pInd); }
// The actual magic shouldn't be hard. Once we trap the signal, find the // recipe, remove it from the parent and add it to the target folder. // It is not easy. Indexes are ephemeral things. We MUST calculate the insert // index after we have removed the recipe. BAD THINGS happen otherwise. // void BtTreeModel::folderChanged(QString name) { BeerXMLElement* test = qobject_cast<BeerXMLElement*>(sender()); QModelIndex ndx, pIndex; bool expand = true; if ( ! test ) return; // Find it. ndx = findElement(test); if ( ! ndx.isValid() ) { Brewtarget::logW("folderChanged:: could not find element"); return; } pIndex = parent(ndx); // Get the parent // If the parent isn't valid, its the root if ( ! pIndex.isValid() ) pIndex = createIndex(0,0,rootItem->child(0)); int i = item(ndx)->childNumber(); // Remove it if ( ! removeRows(i, 1, pIndex) ) { Brewtarget::logW("folderChanged:: could not remove row"); return; } // Find the new parent // That's awkward, but dropping a folder prolly does need a the folder // created. QModelIndex newNdx = findFolder(test->folder(), rootItem->child(0), true); if ( ! newNdx.isValid() ) { newNdx = createIndex(0,0,rootItem->child(0)); expand = false; } BtTreeItem* local = item(newNdx); int j = local->childCount(); if ( ! insertRow(j,newNdx,test,_type) ) { Brewtarget::logW("folderChanged:: could not insert row"); return; } // If we have brewnotes, set them up here. if ( treeMask & RECIPEMASK ) addBrewNoteSubTree(qobject_cast<Recipe*>(test),j,local); if ( expand ) emit expandFolder(treeMask,newNdx); return; }
void BtTreeModel::loadTreeModel() { int i; QModelIndex ndxLocal; BtTreeItem* local = 0; QList<BeerXMLElement*> elems = elements(); foreach( BeerXMLElement* elem, elems ) { if (! elem->folder().isEmpty() ) { ndxLocal = findFolder( elem->folder(), rootItem->child(0), true ); // I cannot imagine this failing, but what the hell if ( ! ndxLocal.isValid() ) { Brewtarget::logW("Invalid return from findFolder in loadTreeModel()"); continue; } local = item(ndxLocal); i = local->childCount(); } else { local = rootItem->child(0); i = local->childCount(); ndxLocal = createIndex(i,0,local); } if ( ! insertRow(i,ndxLocal,elem,_type) ) { Brewtarget::logW("Insert failed in loadTreeModel()"); continue; } // If we have brewnotes, set them up here. if ( treeMask & RECIPEMASK ) addBrewNoteSubTree(qobject_cast<Recipe*>(elem),i,local); observeElement(elem); } }
QModelIndex BtTreeModel::first() { QModelIndex parent; BtTreeItem* pItem; // get the first item in the list, which is the place holder pItem = rootItem->child(0); if ( pItem->childCount() > 0 ) return createIndex(0,0,pItem->child(0)); return QModelIndex(); }
bool BtTreeModel::renameFolder(BtFolder* victim, QString newName) { QModelIndex ndx = findFolder(victim->fullPath(), 0, false); QModelIndex pInd; QString targetPath = newName % "/" % victim->name(); QPair<QString,BtTreeItem*> f; QList<QPair<QString, BtTreeItem*> > folders; // This space is important ^ int i; if ( ! ndx.isValid() ) return false; pInd = parent(ndx); if ( ! pInd.isValid() ) return false; BtTreeItem* start = item(ndx); f.first = targetPath; f.second = start; folders.append(f); while ( ! folders.isEmpty() ) { // This looks weird, but it is needed for later f = folders.takeFirst(); targetPath = f.first; BtTreeItem* target = f.second; // Ok. We have a start and an index. for (i=0; i < target->childCount(); ++i) { BtTreeItem* next = target->child(i); // If a folder, push it onto the folders stack for latter processing if ( next->type() == BtTreeItem::FOLDER ) { QPair<QString,BtTreeItem*> newTarget; newTarget.first = targetPath % "/" % next->name(); newTarget.second = next; folders.append(newTarget); } else // Leafnode next->thing()->setFolder(targetPath); } } // Last thing is to remove the victim. i = start->childNumber(); return removeRows(i, 1, pInd); }
// One find method for all things. This .. is nice QModelIndex BtTreeModel::findElement(BeerXMLElement* thing, BtTreeItem* parent) { BtTreeItem* pItem; QModelIndex pIndex; QList<BtTreeItem*> folders; int i; if ( parent == NULL ) pItem = rootItem->child(0); else pItem = parent; if (! thing ) return createIndex(0,0,pItem); folders.append(pItem); // Recursion. Wonderful. while ( ! folders.isEmpty() ) { BtTreeItem* target = folders.takeFirst(); for(i=0; i < target->childCount(); ++i) { // If we've found what we are looking for, return if ( target->child(i)->thing() == thing ) return createIndex(i,0,target->child(i)); // If we have a folder, or we are looking for a brewnote and have a // recipe in hand, push the child onto the stack if ( target->child(i)->type() == BtTreeItem::FOLDER || (qobject_cast<BrewNote*>(thing) && target->child(i)->type() == BtTreeItem::RECIPE ) ) folders.append(target->child(i)); } } return QModelIndex(); }