]> granicus.if.org Git - transmission/commitdiff
Improve file tree population/update performance
authorMike Gelfand <mikedld@mikedld.com>
Sun, 12 Jul 2015 20:48:54 +0000 (20:48 +0000)
committerMike Gelfand <mikedld@mikedld.com>
Sun, 12 Jul 2015 20:48:54 +0000 (20:48 +0000)
Use simple tokenization instead of splitting the file path into
QStringList for each item. Don't expand each added item separetely
during population/update. Don't expand all the items but just up to the
point where parent has more than one expandable child.

Also, fix items order by sorting items after population/update. Fix
sorting by size on systems where uint64_t != quint64.

qt/FileTreeItem.cc
qt/FileTreeModel.cc
qt/FileTreeModel.h
qt/FileTreeView.cc

index 7c52c81357ecb2f186b84c4727ebdba4c1d7749d..e5780ab2cdd6825003b021eb60119fef2aeecc63 100644 (file)
@@ -119,7 +119,7 @@ FileTreeItem::data (int column, int role) const
             if (role == Qt::DisplayRole)
               value.setValue (sizeString());
             else
-              value.setValue (size ());
+              value.setValue<quint64> (size ());
             break;
 
           case FileTreeModel::COL_PROGRESS:
index 140ceff9235d671ab30b0d046bf24748b93ab336..b9653c46f9acd24ecca1813148f27de256cc54b4 100644 (file)
@@ -9,11 +9,81 @@
 
 #include <cassert>
 
-#include <QStringList>
-
 #include "FileTreeItem.h"
 #include "FileTreeModel.h"
 
+namespace
+{
+  class PathIteratorBase
+  {
+    protected:
+      PathIteratorBase(const QString& path, int slashIndex):
+        myPath (path),
+        mySlashIndex (slashIndex),
+        myToken ()
+      {
+        myToken.reserve (path.size () / 2);
+      }
+
+    protected:
+      const QString& myPath;
+      int mySlashIndex;
+      QString myToken;
+
+      static const QChar SlashChar;
+  };
+
+  const QChar PathIteratorBase::SlashChar = QLatin1Char ('/');
+
+  class ForwardPathIterator: public PathIteratorBase
+  {
+    public:
+      ForwardPathIterator (const QString& path):
+        PathIteratorBase (path, path.size () - 1)
+      {
+      }
+
+      bool hasNext () const
+      {
+        return mySlashIndex > 0;
+      }
+
+      const QString& next ()
+      {
+        int newSlashIndex = myPath.lastIndexOf (SlashChar, mySlashIndex);
+        myToken.truncate (0);
+        myToken += myPath.midRef (newSlashIndex + 1, mySlashIndex - newSlashIndex);
+        mySlashIndex = newSlashIndex - 1;
+        return myToken;
+      }
+  };
+
+  class BackwardPathIterator: public PathIteratorBase
+  {
+    public:
+      BackwardPathIterator (const QString& path):
+        PathIteratorBase (path, 0)
+      {
+      }
+
+      bool hasNext () const
+      {
+        return mySlashIndex < myPath.size ();
+      }
+
+      const QString& next ()
+      {
+        int newSlashIndex = myPath.indexOf (SlashChar, mySlashIndex);
+        if (newSlashIndex == -1)
+          newSlashIndex = myPath.size ();
+        myToken.truncate (0);
+        myToken += myPath.midRef (mySlashIndex, newSlashIndex - mySlashIndex);
+        mySlashIndex = newSlashIndex + 1;
+        return myToken;
+      }
+  };
+}
+
 FileTreeModel::FileTreeModel (QObject * parent, bool isEditable):
   QAbstractItemModel(parent),
   myIsEditable (isEditable),
@@ -221,26 +291,25 @@ FileTreeModel::findItemForFileIndex (int fileIndex) const
 }
 
 void
-FileTreeModel::addFile (int                   fileIndex,
-                        const QString       & filename,
-                        bool                  wanted,
-                        int                   priority,
-                        uint64_t              totalSize,
-                        uint64_t              have,
-                        QList<QModelIndex>  & rowsAdded,
-                        bool                  updateFields)
+FileTreeModel::addFile (int            fileIndex,
+                        const QString& filename,
+                        bool           wanted,
+                        int            priority,
+                        uint64_t       totalSize,
+                        uint64_t       have,
+                        bool           updateFields)
 {
   FileTreeItem * item;
-  QStringList tokens = filename.split (QChar::fromLatin1('/'));
 
   item = findItemForFileIndex (fileIndex);
 
   if (item) // this file is already in the tree, we've added this
     {
       QModelIndex indexWithChangedParents;
-      while (!tokens.isEmpty())
+      ForwardPathIterator filenameIt (filename);
+      while (filenameIt.hasNext ())
         {
-          const QString token = tokens.takeLast();
+          const QString& token = filenameIt.next ();
           const std::pair<int,int> changed = item->update (token, wanted, priority, have, updateFields);
           if (changed.first >= 0)
             {
@@ -260,9 +329,10 @@ FileTreeModel::addFile (int                   fileIndex,
       bool added = false;
 
       item = myRootItem;
-      while (!tokens.isEmpty())
+      BackwardPathIterator filenameIt (filename);
+      while (filenameIt.hasNext ())
         {
-          const QString token = tokens.takeFirst();
+          const QString& token = filenameIt.next ();
           FileTreeItem * child(item->child(token));
           if (!child)
             {
@@ -271,14 +341,12 @@ FileTreeModel::addFile (int                   fileIndex,
               const int n (item->childCount());
 
               beginInsertRows (parentIndex, n, n);
-              if (tokens.isEmpty())
+              if (!filenameIt.hasNext ())
                 child = new FileTreeItem (token, fileIndex, totalSize);
               else
                 child = new FileTreeItem (token);
               item->appendChild (child);
               endInsertRows ();
-
-              rowsAdded.append (indexOf(child, 0));
             }
           item = child;
         }
index 9f122209e0fac064fe2423b41f2f210fb80a6859..c79940a5b96a524524b1a26e694cd3a12f24d092 100644 (file)
@@ -53,7 +53,6 @@ class FileTreeModel: public QAbstractItemModel
     void addFile (int index, const QString& filename,
                   bool wanted, int priority,
                   uint64_t size, uint64_t have,
-                  QList<QModelIndex>& rowsAdded,
                   bool torrentChanged);
 
     QModelIndex parent (const QModelIndex& child, int column) const;
index 6dfed35fac2dbf3ce5b2d922eec07bca6d374d50..d5e9f20cf56b92a332b601faea3ba60e31b4c869 100644 (file)
@@ -169,13 +169,37 @@ FileTreeView::keyPressEvent (QKeyEvent * event)
 void
 FileTreeView::update (const FileList& files, bool updateFields)
 {
+  const bool modelWasEmpty = myProxy->rowCount () == 0;
+
   for (const TorrentFile& file: files)
+    myModel->addFile (file.index, file.filename, file.wanted, file.priority, file.size, file.have, updateFields);
+
+  if (modelWasEmpty)
     {
-      QList<QModelIndex> added;
-      myModel->addFile (file.index, file.filename, file.wanted, file.priority, file.size, file.have, added, updateFields);
-      for (const QModelIndex& i: added)
-        expand (myProxy->mapFromSource(i));
+      // expand up until the item with more than one expandable child
+      for (QModelIndex index = myProxy->index (0, 0); index.isValid ();)
+        {
+          const QModelIndex oldIndex = index;
+
+          expand (oldIndex);
+
+          index = QModelIndex ();
+          for (int i = 0, count = myProxy->rowCount (oldIndex); i < count; ++i)
+            {
+              const QModelIndex newIndex = myProxy->index (i, 0, oldIndex);
+              if (myProxy->rowCount (newIndex) == 0)
+                continue;
+              if (index.isValid ())
+                {
+                  index = QModelIndex ();
+                  break;
+                }
+              index = newIndex;
+            }
+        }
     }
+
+  myProxy->sort (header ()->sortIndicatorSection (), header ()->sortIndicatorOrder ());
 }
 
 void