# # # patch "src/model/Inventory.cpp" # from [71bba569c26554a91a44e6cbd150cec395dce7fe] # to [23d0782e08e39c17f7928b2eb44e6ed1fec91f49] # # patch "src/model/Inventory.h" # from [b47df84df275352abd1e71ca41c128fba53fa0e0] # to [323c88751637a3b78608bf9b980a0dde7bd25c0d] # ============================================================ --- src/model/Inventory.cpp 71bba569c26554a91a44e6cbd150cec395dce7fe +++ src/model/Inventory.cpp 23d0782e08e39c17f7928b2eb44e6ed1fec91f49 @@ -31,11 +31,12 @@ Inventory::Inventory(QObject * parent) { rootItem = new ModelItem("__root__"); rootItem->setParent(rootItem); - +/* connect( this, SIGNAL(modelReset()), this, SLOT(setWorkspacePath()) ); +*/ } Inventory::~Inventory() @@ -112,6 +113,13 @@ void Inventory::readInventory(const QStr void Inventory::readInventory(const QString & path) { + static bool debugRead = false; + if (debugRead) + { + return; + } + debugRead = true; + I(!workspacePath.isEmpty()); QStringList cmd = QStringList() << "inventory"; @@ -126,6 +134,7 @@ void Inventory::readInventory(const QStr // if requested, just read one directory level ahead // (useful for big directory trees) + if (Settings::getBool("ReadWorkspaceIncrementally", true)) { opts << "depth" << QString::number(1); @@ -135,6 +144,16 @@ void Inventory::readInventory(const QStr AutomateCommand::enqueueWorkspaceTask(workspacePath, task); } +/*! + @fixme + The whole item adding procedurecould eventually make problems + if inventory is executed with a path which was renamed. The + inventory output then contains another stanza of a path which + was not yet read in, so we have no plan where to tack this on. + A possible resolution would be to enqueue a new inventory + request with the baseDir right here, delete the node and + continue with the next one +*/ void Inventory::processTaskResult(const MonotoneTask & task) { if (task.getReturnCode() != 0) @@ -171,9 +190,24 @@ void Inventory::processTaskResult(const BasicIOParser parser(task.getOutputUtf8()); I(parser.parse()); StanzaList stanzas = parser.getStanzas(); - QString lastBaseDir; - QModelIndexList parentsWithChildren; + ModelItem * parentItem = rootItem; + if (itemMap.contains(queriedPath)) + { + parentItem = itemMap.value(queriedPath)->parent(); + } + + // + // For the lazy population code to work properly, Qt needs to get + // all items added within their very own beginInsertRows and + // endInsertRows. To prevent that we need to call those two for each + // single item, we do not yet set the parent / child dependencies just + // now, but record them temporarily in parentChildRelations. + // If we've processed all stanzas, we rework these relations into + // actual relations and notify Qt about that in insertRowsRecursive + // + QMap > parentChildRelations; + QMap tempItemMap; foreach (Stanza st, stanzas) { InventoryItem * item = new InventoryItem(st); @@ -190,51 +224,23 @@ void Inventory::processTaskResult(const if (item->isDirectory() && (queriedDepth == -1 || queriedDepth < itemDepth)) { PseudoItem * cdUp = new PseudoItem("..", PseudoItem::CdUp); - item->appendChild(cdUp); - parentsWithChildren.append(indexFromItem(item, 0)); + parentChildRelations[item].append(cdUp); } - // if this item replaces an existing item, delete it and all possible - // children underknees - if (itemMap.contains(path)) - { - InventoryItem * oldItem = itemMap.value(path); - QModelIndex index = indexFromItem(oldItem, 0); - I(index.isValid()); - int row = oldItem->row(); - removeRowsRecursive(index.parent(), row, row); - } - ModelItem * parentItem; - if (path.isEmpty()) - { - parentItem = rootItem; - } + QString baseDir = item->getBaseDirectory(); + + ModelItem * parent = 0; + if (tempItemMap.contains(baseDir)) + parent = tempItemMap.value(baseDir); else - { - QString baseDir = item->getBaseDirectory(); - // FIXME: this could eventually make problems if inventory is - // executed with a path which was renamed. The inventory output - // then contains another stanza of a path which was not yet - // read in, so we have no plan where to tack this on. - // A possible resolution would be to enqueue a new inventory - // request with the baseDir right here, delete the node and - // continue with the next one - I(itemMap.contains(baseDir)); - parentItem = itemMap.value(baseDir); - } + parent = parentItem; - QModelIndex parentIndex = indexFromItem(parentItem, 0); - itemMap.insert(path, item); - parentItem->appendChild(item); + I(parent); + parentChildRelations[parent].append(item); + tempItemMap.insert(path, item); } - // we've remembered all the model indexes which got real children - // now inform Qt at a glance what we've just inserted - foreach (QModelIndex index, parentsWithChildren) - { - beginInsertRows(index, 0, rowCount(index)); - endInsertRows(); - } + insertRowsRecursive(parentItem, parentChildRelations); // // This is a bit of a hack: Since we replace the original item each @@ -528,6 +534,63 @@ QMap Inventory return unaccountedRenames; } +void Inventory::insertRowsRecursive(ModelItem * parentItem, const QMap > & parentChildRelations) +{ + I(parentChildRelations.contains(parentItem)); + QModelIndex parentIndex = indexFromItem(parentItem, 0); + I(parentIndex.isValid() || parentItem->isRoot()); + const QList & children = parentChildRelations.value(parentItem); + I(children.size() > 0); + + // + // ensure that old rows get deleted at first + // + foreach (ModelItem * item, children) + { + InventoryItem * invitem = dynamic_cast(item); + if (!invitem) continue; + + QString path = invitem->getPath(); + if (itemMap.contains(path)) + { + InventoryItem * oldItem = itemMap.value(path); + int row = oldItem->row(); + L(QString("removing %1 and children").arg(oldItem->getLabel())); + removeRowsRecursive(parentIndex, row, row); + } + } + + // + // now do the actual row insertion while notifying Qt properly about that + // + L(QString("adding %1 children for %2").arg(children.size()).arg(parentItem->getLabel())); + int parentRowCount = rowCount(parentIndex); + beginInsertRows(parentIndex, parentRowCount, parentRowCount + children.size() - 1); + foreach (ModelItem * item, children) + { + InventoryItem * invitem = dynamic_cast(item); + if (invitem) + { + QString path = invitem->getPath(); + L(QString("inserting %1").arg(path)); + I(!itemMap.contains(path)); + itemMap.insert(path, invitem); + } + parentItem->appendChild(item); + } + endInsertRows(); + + // + // finally check if the just added items have children we need + // to insert recursively + // + foreach (ModelItem * item, children) + { + if (parentChildRelations.contains(item)) + insertRowsRecursive(item, parentChildRelations); + } +} + void Inventory::removeRowsRecursive(const QModelIndex & parent, int startRow, int endRow) { I(startRow >= 0); ============================================================ --- src/model/Inventory.h b47df84df275352abd1e71ca41c128fba53fa0e0 +++ src/model/Inventory.h 323c88751637a3b78608bf9b980a0dde7bd25c0d @@ -56,6 +56,7 @@ private: private: void processTaskResult(const MonotoneTask &); QModelIndex indexFromItem(ModelItem *, int) const; + void insertRowsRecursive(ModelItem *, const QMap > &); void removeRowsRecursive(const QModelIndex &, int, int); void readInventory(const QString &);