Browse Source

bug-fix: * will recursively expand the directory tree causing crash

We build the complete subtree before expanding to avoid crash.
Le Tan 8 years ago
parent
commit
5ad99ee9b8
3 changed files with 71 additions and 18 deletions
  1. 44 15
      src/vdirectorytree.cpp
  2. 23 2
      src/vdirectorytree.h
  3. 4 1
      src/vfilelist.cpp

+ 44 - 15
src/vdirectorytree.cpp

@@ -132,7 +132,7 @@ void VDirectoryTree::updateDirectoryTree()
         fillTreeItem(*item, dir->getName(), dir,
                      QIcon(":/resources/icons/dir_item.svg"));
 
-        updateDirectoryTreeOne(item, 1);
+        buildSubTree(item, 1);
     }
 
     if (!restoreCurrentItem()) {
@@ -155,12 +155,12 @@ bool VDirectoryTree::restoreCurrentItem()
     return false;
 }
 
-void VDirectoryTree::updateDirectoryTreeOne(QTreeWidgetItem *p_parent, int depth)
+void VDirectoryTree::buildSubTree(QTreeWidgetItem *p_parent, int p_depth)
 {
-    Q_ASSERT(p_parent->childCount() == 0);
-    if (depth <= 0) {
+    if (p_depth == 0) {
         return;
     }
+
     VDirectory *dir = getVDirectory(p_parent);
     if (!dir->open()) {
         VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
@@ -169,16 +169,25 @@ void VDirectoryTree::updateDirectoryTreeOne(QTreeWidgetItem *p_parent, int depth
                             QMessageBox::Ok, QMessageBox::Ok, this);
         return;
     }
-    const QVector<VDirectory *> &subDirs = dir->getSubDirs();
-    for (int i = 0; i < subDirs.size(); ++i) {
-        VDirectory *subDir = subDirs[i];
-        QTreeWidgetItem *item = new QTreeWidgetItem(p_parent);
 
-        fillTreeItem(*item, subDir->getName(), subDir,
-                     QIcon(":/resources/icons/dir_item.svg"));
+    if (p_parent->childCount() > 0) {
+        // This directory has been built before. Try its children directly.
+        for (int i = 0; i < p_parent->childCount(); ++i) {
+            buildSubTree(p_parent->child(i), p_depth -1);
+        }
+    } else {
+        const QVector<VDirectory *> &subDirs = dir->getSubDirs();
+        for (int i = 0; i < subDirs.size(); ++i) {
+            VDirectory *subDir = subDirs[i];
+            QTreeWidgetItem *item = new QTreeWidgetItem(p_parent);
+
+            fillTreeItem(*item, subDir->getName(), subDir,
+                         QIcon(":/resources/icons/dir_item.svg"));
 
-        updateDirectoryTreeOne(item, depth - 1);
+            buildSubTree(item, p_depth - 1);
+        }
     }
+
     if (dir->isExpanded()) {
         expandItem(p_parent);
     }
@@ -197,7 +206,6 @@ void VDirectoryTree::handleItemExpanded(QTreeWidgetItem *p_item)
     dir->setExpanded(true);
 }
 
-// Update @p_item's children items
 void VDirectoryTree::updateChildren(QTreeWidgetItem *p_item)
 {
     Q_ASSERT(p_item);
@@ -205,12 +213,14 @@ void VDirectoryTree::updateChildren(QTreeWidgetItem *p_item)
     if (nrChild == 0) {
         return;
     }
+
     for (int i = 0; i < nrChild; ++i) {
         QTreeWidgetItem *childItem = p_item->child(i);
         if (childItem->childCount() > 0) {
             continue;
         }
-        updateDirectoryTreeOne(childItem, 1);
+
+        buildSubTree(childItem, 1);
     }
 }
 
@@ -252,7 +262,7 @@ void VDirectoryTree::updateItemChildren(QTreeWidgetItem *p_item)
                 item = new QTreeWidgetItem(this);
             }
             fillTreeItem(*item, dir->getName(), dir, QIcon(":/resources/icons/dir_item.svg"));
-            updateDirectoryTreeOne(item, 1);
+            buildSubTree(item, 1);
         }
         expandItemTree(item);
     }
@@ -577,6 +587,7 @@ void VDirectoryTree::keyPressEvent(QKeyEvent *event)
         if (item) {
             item->setExpanded(!item->isExpanded());
         }
+
         break;
     }
 
@@ -589,6 +600,7 @@ void VDirectoryTree::keyPressEvent(QKeyEvent *event)
             QCoreApplication::postEvent(this, downEvent);
             return;
         }
+
         break;
     }
 
@@ -601,6 +613,21 @@ void VDirectoryTree::keyPressEvent(QKeyEvent *event)
             QCoreApplication::postEvent(this, upEvent);
             return;
         }
+
+        break;
+    }
+
+    case Qt::Key_Asterisk:
+    {
+        if (modifiers == Qt::ShiftModifier) {
+            // *, by default will expand current item recursively.
+            // We build the tree recursively before the expanding.
+            QTreeWidgetItem *item = currentItem();
+            if (item) {
+                buildSubTree(item, -1);
+            }
+        }
+
         break;
     }
 
@@ -730,7 +757,7 @@ QTreeWidgetItem *VDirectoryTree::expandToVDirectory(const VDirectory *p_director
         }
         int nrChild = pItem->childCount();
         if (nrChild == 0) {
-            updateDirectoryTreeOne(pItem, 1);
+            buildSubTree(pItem, 1);
         }
         nrChild = pItem->childCount();
         for (int i = 0; i < nrChild; ++i) {
@@ -748,11 +775,13 @@ void VDirectoryTree::expandItemTree(QTreeWidgetItem *p_item)
     if (!p_item) {
         return;
     }
+
     VDirectory *dir = getVDirectory(p_item);
     int nrChild = p_item->childCount();
     for (int i = 0; i < nrChild; ++i) {
         expandItemTree(p_item->child(i));
     }
+
     if (dir->isExpanded()) {
         Q_ASSERT(nrChild > 0);
         expandItem(p_item);

+ 23 - 2
src/vdirectorytree.h

@@ -40,6 +40,9 @@ public slots:
     void newRootDirectory();
     void deleteDirectory();
     void editDirectoryInfo();
+
+    // Clear and re-build the whole directory tree.
+    // Do not load all the sub-directories at once.
     void updateDirectoryTree();
 
 private slots:
@@ -58,9 +61,21 @@ protected:
     void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
 
 private:
-    void updateDirectoryTreeOne(QTreeWidgetItem *p_parent, int depth);
+    // Build the subtree of @p_parent recursively to the depth @p_depth.
+    // Item @p_parent must not be built before.
+    // Will expand the item if the corresponding directory was expanded before.
+    // @p_depth: valid only when greater than 0.
+    void updateDirectoryTreeOne(QTreeWidgetItem *p_parent, int p_depth);
+
+    // Build the subtree of @p_parent recursively to the depth @p_depth.
+    // @p_depth: negative - infinite levels.
+    // Will expand the item if the corresponding directory was expanded before.
+    void buildSubTree(QTreeWidgetItem *p_parent, int p_depth);
+
+    // Fill the content of a tree item.
     void fillTreeItem(QTreeWidgetItem &p_item, const QString &p_name,
                       VDirectory *p_directory, const QIcon &p_icon);
+
     void initActions();
     // Update @p_item's direct children only: deleted, added, renamed.
     void updateItemChildren(QTreeWidgetItem *p_item);
@@ -72,11 +87,16 @@ private:
     void pasteDirectories(VDirectory *p_destDir);
     bool copyDirectory(VDirectory *p_destDir, const QString &p_destName,
                        VDirectory *p_srcDir, bool p_cut);
+
+    // Build the subtree of @p_item's children if it has not been built yet.
     void updateChildren(QTreeWidgetItem *p_item);
+
     // Expand/create the directory tree nodes to @p_directory.
     QTreeWidgetItem *expandToVDirectory(const VDirectory *p_directory);
-    // Expand the tree under @p_item according to VDirectory.isOpened().
+
+    // Expand the currently-built subtree of @p_item according to VDirectory.isExpanded().
     void expandItemTree(QTreeWidgetItem *p_item);
+
     QList<QTreeWidgetItem *> getVisibleItems() const;
     QList<QTreeWidgetItem *> getVisibleChildItems(const QTreeWidgetItem *p_item) const;
     bool restoreCurrentItem();
@@ -86,6 +106,7 @@ private:
     QVector<QPointer<VDirectory> > m_copiedDirs;
     VEditArea *m_editArea;
 
+    // Each notebook's current item's VDirectory.
     QHash<VNotebook *, VDirectory *> m_notebookCurrentDirMap;
 
     // Actions

+ 4 - 1
src/vfilelist.cpp

@@ -637,6 +637,7 @@ void VFileList::showNavigation()
 
     // Generate labels for visible items.
     auto items = getVisibleItems();
+    int itemWidth = rect().width();
     for (int i = 0; i < 26 && i < items.size(); ++i) {
         QChar key('a' + i);
         m_keyMap[key] = items[i];
@@ -644,8 +645,10 @@ void VFileList::showNavigation()
         QString str = QString(m_majorKey) + key;
         QLabel *label = new QLabel(str, this);
         label->setStyleSheet(g_vnote->getNavigationLabelStyle(str));
-        label->move(fileList->visualItemRect(items[i]).topLeft());
         label->show();
+        QRect rect = fileList->visualItemRect(items[i]);
+        // Display the label at the end to show the file name.
+        label->move(rect.x() + itemWidth - label->width(), rect.y());
         m_naviLabels.append(label);
     }
 }