source: trunk/qt/file-tree.cc @ 13929

Last change on this file since 13929 was 13929, checked in by jordan, 10 years ago

(qt) #5252 'file-renaming issues in Qt client': hide invisible columns in file-tree

  • Property svn:keywords set to Date Rev Author Id
File size: 21.1 KB
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
7 *
8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
9 *
10 * $Id: file-tree.cc 13929 2013-02-01 22:08:09Z jordan $
11 */
12
13#include <cassert>
14
15#include <QApplication>
16#include <QHeaderView>
17#include <QPainter>
18#include <QResizeEvent>
19#include <QSortFilterProxyModel>
20#include <QStringList>
21
22#include <libtransmission/transmission.h> // priorities
23
24#include "file-tree.h"
25#include "formatter.h"
26#include "hig.h"
27#include "torrent.h" // FileList
28#include "utils.h" // mime icons
29
30enum
31{
32  COL_NAME,
33  FIRST_VISIBLE_COLUMN = COL_NAME,
34  COL_PROGRESS,
35  COL_WANTED,
36  COL_PRIORITY,
37  LAST_VISIBLE_COLUMN = COL_PRIORITY,
38
39  COL_FILE_INDEX,
40  NUM_COLUMNS
41};
42
43/****
44*****
45****/
46
47const QHash<QString,int>&
48FileTreeItem :: getMyChildRows ()
49{
50  const size_t n = childCount();
51
52  // ensure that all the rows are hashed
53  while (myFirstUnhashedRow < n)
54    {
55      myChildRows.insert (myChildren[myFirstUnhashedRow]->name(),
56                          myFirstUnhashedRow);
57      ++myFirstUnhashedRow;
58    }
59
60  return myChildRows;
61}
62
63
64FileTreeItem :: ~FileTreeItem ()
65{
66  assert(myChildren.isEmpty());
67
68  if (myParent != 0)
69    {
70      const int pos = row();
71      assert ((pos>=0) && "couldn't find child in parent's lookup");
72      myParent->myChildren.removeAt(pos);
73      myParent->myChildRows.remove(name());
74      myParent->myFirstUnhashedRow = pos;
75    }
76}
77
78void
79FileTreeItem :: appendChild (FileTreeItem * child)
80{
81  const size_t n = childCount();
82  child->myParent = this;
83  myChildren.append (child);
84  myFirstUnhashedRow = n;
85}
86
87FileTreeItem *
88FileTreeItem :: child (const QString& filename)
89{
90  FileTreeItem * item(0);
91
92  const int row = getMyChildRows().value (filename, -1);
93  if (row != -1)
94    {
95      item = child (row);
96      assert (filename == item->name());
97    }
98
99  return item;
100}
101
102int
103FileTreeItem :: row () const
104{
105  int i(-1);
106
107  if(myParent)
108    {
109      i = myParent->getMyChildRows().value (name(), -1);
110      assert (this == myParent->myChildren[i]);
111    }
112
113  return i;
114}
115
116QVariant
117FileTreeItem :: data (int column, int role) const
118{
119  QVariant value;
120
121  if (column == COL_FILE_INDEX)
122    {
123      return myFileIndex;
124    }
125  else if (role == Qt::EditRole)
126    {
127      if (column == 0)
128        value.setValue (name());
129    }
130  else if (role == Qt::DisplayRole)
131    {
132      switch(column)
133       {
134         case COL_NAME:
135           value.setValue (fileSizeName());
136           break;
137
138         case COL_PROGRESS:
139           value.setValue (progress());
140           break;
141
142         case COL_WANTED:
143           value.setValue (isSubtreeWanted());
144           break;
145
146         case COL_PRIORITY:
147           value.setValue (priorityString());
148           break;
149        }
150    }
151
152  return value;
153}
154
155void
156FileTreeItem :: getSubtreeSize (uint64_t& have, uint64_t& total) const
157{
158  have += myHaveSize;
159  total += myTotalSize;
160
161  foreach(const FileTreeItem * i, myChildren)
162    i->getSubtreeSize(have, total);
163}
164
165double
166FileTreeItem :: progress () const
167{
168  double d(0);
169  uint64_t have(0), total(0);
170
171  getSubtreeSize(have, total);
172  if (total)
173    d = have / (double)total;
174
175  return d;
176}
177
178QString
179FileTreeItem :: fileSizeName () const
180{
181  uint64_t have(0), total(0);
182  QString str;
183  getSubtreeSize(have, total);
184  str = QString(name() + " (%1)").arg(Formatter::sizeToString(total));
185  return str;
186}
187
188#include <iostream>
189
190bool
191FileTreeItem :: update (const QString& name,
192                        bool           wanted,
193                        int            priority,
194                        uint64_t       haveSize,
195                        bool           updateFields)
196{
197  bool changed = false;
198
199  if (myName != name)
200    {
201      if (myParent)
202        myParent->myFirstUnhashedRow = row();
203
204      myName = name;
205      changed = true;
206    }
207
208  if (fileIndex() != -1)
209    {
210      if (myHaveSize != haveSize)
211        {
212          myHaveSize = haveSize;
213          changed = true;
214        }
215
216      if (updateFields)
217        {
218          if (myIsWanted != wanted)
219            {
220              myIsWanted = wanted;
221              changed = true;
222            }
223
224          if (myPriority != priority)
225            {
226              myPriority = priority;
227              changed = true;
228            }
229        }
230    }
231
232  return changed;
233}
234
235QString
236FileTreeItem :: priorityString () const
237{
238  const int i = priority();
239
240  switch (i)
241    {
242      case LOW:    return tr("Low");
243      case HIGH:   return tr("High");
244      case NORMAL: return tr("Normal");
245      default:     return tr("Mixed");
246    }
247}
248
249int
250FileTreeItem :: priority () const
251{
252  int i(0);
253
254  if (myChildren.isEmpty())
255    {
256      switch (myPriority)
257        {
258          case TR_PRI_LOW:
259            i |= LOW;
260            break;
261
262          case TR_PRI_HIGH:
263            i |= HIGH;
264            break;
265
266          default:
267            i |= NORMAL;
268            break;
269        }
270    }
271
272  foreach (const FileTreeItem * child, myChildren)
273    i |= child->priority();
274
275  return i;
276}
277
278void
279FileTreeItem :: setSubtreePriority (int i, QSet<int>& ids)
280{
281  if (myPriority != i)
282    {
283      myPriority = i;
284
285      if (myFileIndex >= 0)
286        ids.insert (myFileIndex);
287    }
288
289  foreach (FileTreeItem * child, myChildren)
290    child->setSubtreePriority (i, ids);
291}
292
293void
294FileTreeItem :: twiddlePriority (QSet<int>& ids, int& p)
295{
296  const int old(priority());
297
298  if (old & LOW)
299    p = TR_PRI_NORMAL;
300  else if (old & NORMAL)
301    p = TR_PRI_HIGH;
302  else
303    p = TR_PRI_LOW;
304
305  setSubtreePriority (p, ids);
306}
307
308int
309FileTreeItem :: isSubtreeWanted () const
310{
311  if(myChildren.isEmpty())
312    return myIsWanted ? Qt::Checked : Qt::Unchecked;
313
314  int wanted(-1);
315  foreach (const FileTreeItem * child, myChildren)
316    {
317      const int childWanted = child->isSubtreeWanted();
318
319      if (wanted == -1)
320        wanted = childWanted;
321
322      if (wanted != childWanted)
323        wanted = Qt::PartiallyChecked;
324
325      if (wanted == Qt::PartiallyChecked)
326        return wanted;
327    }
328
329  return wanted;
330}
331
332void
333FileTreeItem :: setSubtreeWanted (bool b, QSet<int>& ids)
334{
335  if (myIsWanted != b)
336    {
337      myIsWanted = b;
338
339      if (myFileIndex >= 0)
340        ids.insert(myFileIndex);
341    }
342
343  foreach (FileTreeItem * child, myChildren)
344    child->setSubtreeWanted (b, ids);
345}
346
347void
348FileTreeItem :: twiddleWanted (QSet<int>& ids, bool& wanted)
349{
350  wanted = isSubtreeWanted() != Qt::Checked;
351  setSubtreeWanted (wanted, ids);
352}
353
354/***
355****
356****
357***/
358
359FileTreeModel :: FileTreeModel (QObject *parent, bool isEditable):
360  QAbstractItemModel(parent),
361  myRootItem (new FileTreeItem),
362  myIsEditable (isEditable)
363{
364}
365
366FileTreeModel :: ~FileTreeModel()
367{
368  clear();
369
370  delete myRootItem;
371}
372
373FileTreeItem *
374FileTreeModel :: itemFromIndex (const QModelIndex& index) const
375{
376  return static_cast<FileTreeItem*>(index.internalPointer()); 
377}
378
379QVariant
380FileTreeModel :: data (const QModelIndex &index, int role) const
381{
382  QVariant value;
383
384  if (index.isValid())
385    value = itemFromIndex(index)->data (index.column(), role);
386
387  return value;
388}
389
390Qt::ItemFlags
391FileTreeModel :: flags (const QModelIndex& index) const
392{
393  int i(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
394
395  if(myIsEditable && (index.column() == COL_NAME))
396    i |= Qt::ItemIsEditable;
397
398  if(index.column() == COL_WANTED)
399    i |= Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
400
401  return (Qt::ItemFlags)i;
402}
403
404bool
405FileTreeModel :: setData (const QModelIndex& index, const QVariant& newname, int role)
406{
407  if (role == Qt::EditRole)
408    {
409      QString oldpath;
410      QModelIndex walk = index;
411      FileTreeItem * item = itemFromIndex (index);
412
413      while (item && !item->name().isEmpty())
414        {
415          if (oldpath.isEmpty())
416            oldpath = item->name();
417          else
418            oldpath = item->name() + "/" + oldpath;
419          item = item->parent ();
420        }
421
422      emit pathEdited (oldpath, newname.toString());
423    }
424
425  return false; // don't update the view until the session confirms the change
426}
427
428QVariant
429FileTreeModel :: headerData (int column, Qt::Orientation orientation, int role) const
430{
431  QVariant data;
432
433  if (orientation==Qt::Horizontal && role==Qt::DisplayRole)
434    {
435      switch (column)
436        {
437          case COL_NAME:
438            data.setValue (tr("File"));
439            break;
440
441          case COL_PROGRESS:
442            data.setValue (tr("Progress"));
443            break;
444
445          case COL_WANTED:
446            data.setValue (tr("Download"));
447            break;
448
449          case COL_PRIORITY:
450            data.setValue (tr("Priority")); 
451            break;
452
453          default:
454            break;
455        }
456    }
457
458  return data;
459}
460
461QModelIndex
462FileTreeModel :: index (int row, int column, const QModelIndex& parent) const
463{
464  QModelIndex i;
465
466  if (hasIndex (row, column, parent))
467    {
468      FileTreeItem * parentItem;
469
470      if (!parent.isValid ())
471        parentItem = myRootItem;
472      else
473        parentItem = itemFromIndex (parent);
474
475      FileTreeItem * childItem = parentItem->child (row);
476
477      if (childItem)
478        i = createIndex (row, column, childItem);
479    }
480
481  return i;
482}
483
484QModelIndex
485FileTreeModel :: parent (const QModelIndex& child) const
486{
487  return parent (child, 0); // QAbstractItemModel::parent() wants col 0
488}
489
490QModelIndex
491FileTreeModel :: parent (const QModelIndex& child, int column) const
492{
493  QModelIndex parent;
494
495  if (child.isValid())
496    parent = indexOf (itemFromIndex(child)->parent(), column);
497
498  return parent;
499}
500
501int
502FileTreeModel :: rowCount (const QModelIndex& parent) const
503{
504  FileTreeItem * parentItem;
505
506  if (parent.isValid())
507    parentItem = itemFromIndex (parent);
508  else
509    parentItem = myRootItem;
510
511  return parentItem->childCount();
512}
513
514int
515FileTreeModel :: columnCount (const QModelIndex &parent) const
516{
517  Q_UNUSED(parent);
518
519  return NUM_COLUMNS;
520}
521
522QModelIndex
523FileTreeModel :: indexOf (FileTreeItem * item, int column) const
524{
525  if (!item || item==myRootItem)
526    return QModelIndex();
527
528  return createIndex(item->row(), column, item);
529}
530
531void
532FileTreeModel :: clearSubtree (const QModelIndex& top)
533{
534  size_t i = rowCount (top);
535
536  while (i > 0)
537    clearSubtree(index(--i, 0, top));
538
539  delete static_cast<FileTreeItem*>(itemFromIndex(top));
540}
541
542void
543FileTreeModel :: clear ()
544{
545  clearSubtree (QModelIndex());
546
547  reset ();
548}
549
550FileTreeItem *
551FileTreeModel :: findItemForFileIndex (int fileIndex) const
552{
553  FileTreeItem * ret = 0;
554
555  QModelIndexList indices = match (index (0,COL_FILE_INDEX),
556                                   Qt::DisplayRole,
557                                   fileIndex,
558                                   1,
559                                   Qt::MatchFlags (Qt::MatchExactly | Qt::MatchRecursive));
560
561  if (!indices.isEmpty ())
562    {
563      QModelIndex& index = indices.front ();
564      if (index.isValid())
565        ret = itemFromIndex (index);
566    }
567
568  return ret;
569}
570
571void
572FileTreeModel :: itemChanged (FileTreeItem * item)
573{
574  dataChanged (indexOf(item, FIRST_VISIBLE_COLUMN), indexOf(item, LAST_VISIBLE_COLUMN));
575}
576
577void
578FileTreeModel :: addFile (int                   fileIndex,
579                          const QString       & filename,
580                          bool                  wanted,
581                          int                   priority,
582                          uint64_t              totalSize,
583                          uint64_t              have,
584                          QList<QModelIndex>  & rowsAdded,
585                          bool                  updateFields)
586{
587  bool added = false;
588  FileTreeItem * item;
589  QStringList tokens = filename.split (QChar::fromAscii('/'));
590
591  item = findItemForFileIndex (fileIndex);
592
593  if (item) // this file is already in the tree, we've added this
594    {
595      while (!tokens.isEmpty())
596        {
597          const QString token = tokens.takeLast();
598          if (item->update (token, wanted, priority, have, updateFields))
599            itemChanged (item);
600          item = item->parent();
601        }
602      assert (item == myRootItem);
603    }
604  else // we haven't build the FileTreeItems for these tokens yet
605    {
606      item = myRootItem;
607      while (!tokens.isEmpty())
608        {
609          const QString token = tokens.takeFirst();
610          FileTreeItem * child(item->child(token));
611          if (!child)
612            {
613              added = true;
614              QModelIndex parentIndex (indexOf(item, 0));
615              const int n (item->childCount());
616
617              beginInsertRows (parentIndex, n, n);
618              if (tokens.isEmpty())
619                child = new FileTreeItem (token, fileIndex, totalSize);
620              else
621                child = new FileTreeItem (token);
622              item->appendChild (child);
623              endInsertRows ();
624
625              rowsAdded.append (indexOf(child, 0));
626            }
627          item = child;
628        }
629
630      if (item != myRootItem)
631        {
632          assert (item->fileIndex() == fileIndex);
633          assert (item->totalSize() == totalSize);
634
635          if (item->update (item->name(), wanted, priority, have, added || updateFields))
636            itemChanged (item);
637        }
638    }
639}
640
641void
642FileTreeModel :: parentsChanged (const QModelIndex& index, int column)
643{
644  QModelIndex walk = index;
645
646  for (;;)
647    {
648      walk = parent(walk, column);
649      if(!walk.isValid())
650        break;
651
652      dataChanged(walk, walk);
653    }
654}
655
656void
657FileTreeModel :: subtreeChanged (const QModelIndex& index, int column)
658{
659  const int childCount = rowCount (index);
660  if (!childCount)
661    return;
662
663  // tell everyone that this tier changed
664  dataChanged (index.child(0,column), index.child(childCount-1,column));
665
666  // walk the subtiers
667  for (int i=0; i<childCount; ++i)
668    subtreeChanged (index.child(i,column), column);
669}
670
671void
672FileTreeModel :: clicked (const QModelIndex& index)
673{
674  const int column (index.column());
675
676  if (!index.isValid())
677    return;
678
679  if (column == COL_WANTED)
680    {
681      bool want;
682      QSet<int> file_ids;
683      FileTreeItem * item;
684
685      item = itemFromIndex (index);
686      item->twiddleWanted (file_ids, want);
687      emit wantedChanged (file_ids, want);
688
689      dataChanged (index, index);
690      parentsChanged (index, column);
691      subtreeChanged (index, column);
692    }
693  else if (column == COL_PRIORITY)
694    {
695      int priority;
696      QSet<int> file_ids;
697      FileTreeItem * item;
698
699      item = itemFromIndex (index);
700      item->twiddlePriority (file_ids, priority);
701      emit priorityChanged (file_ids, priority);
702
703      dataChanged(index, index);
704      parentsChanged(index, column);
705      subtreeChanged(index, column);
706    }
707}
708
709/****
710*****
711****/
712
713QSize
714FileTreeDelegate :: sizeHint(const QStyleOptionViewItem& item, const QModelIndex& index) const
715{
716  QSize size;
717
718  switch(index.column())
719    {
720      case COL_NAME:
721        {
722          const QFontMetrics fm(item.font);
723          const QString text = index.data().toString();
724          const int iconSize = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
725          size.rwidth() = HIG::PAD_SMALL + iconSize;
726          size.rheight() = std::max(iconSize, fm.height());
727          break;
728        }
729
730      case COL_PROGRESS:
731      case COL_WANTED:
732        size = QSize(20, 1);
733        break;
734
735      default:
736        {
737          const QFontMetrics fm(item.font);
738          const QString text = index.data().toString();
739          size = fm.size(0, text);
740          break;
741        }
742    }
743
744  size.rheight() += 8; // make the spacing a little nicer
745  return size;
746}
747
748void
749FileTreeDelegate :: paint (QPainter                    * painter,
750                           const QStyleOptionViewItem  & option,
751                           const QModelIndex           & index) const
752{
753  const int column(index.column());
754
755  if ((column != COL_PROGRESS) && (column != COL_WANTED) && (column != COL_NAME))
756    {
757      QItemDelegate::paint(painter, option, index);
758      return;
759    }
760
761  QStyle * style (QApplication :: style());
762  if (option.state & QStyle::State_Selected)
763    painter->fillRect (option.rect, option.palette.highlight());
764  painter->save();
765  if (option.state & QStyle::State_Selected)
766    painter->setBrush (option.palette.highlightedText());
767
768  if (column == COL_NAME)
769    {
770      // draw the file icon
771      static const int iconSize (style->pixelMetric(QStyle :: PM_SmallIconSize));
772      const QRect iconArea (option.rect.x(),
773                            option.rect.y() + (option.rect.height()-iconSize)/2,
774                            iconSize, iconSize);
775      QIcon icon;
776      if (index.model()->hasChildren(index))
777        {
778          icon = style->standardIcon(QStyle::StandardPixmap(QStyle::SP_DirOpenIcon));
779        }
780      else
781        {
782          QString name = index.data().toString();
783          icon = Utils :: guessMimeIcon (name.left(name.lastIndexOf(" (")));
784        }
785      icon.paint (painter, iconArea, Qt::AlignCenter, QIcon::Normal, QIcon::On);
786
787      // draw the name
788      QStyleOptionViewItem tmp (option);
789      tmp.rect.setWidth (option.rect.width() - iconArea.width() - HIG::PAD_SMALL);
790      tmp.rect.moveRight (option.rect.right());
791      QItemDelegate::paint (painter, tmp, index);
792    }
793  else if(column == COL_PROGRESS)
794    {
795      QStyleOptionProgressBar p;
796      p.state = option.state | QStyle::State_Small;
797      p.direction = QApplication::layoutDirection();
798      p.rect = option.rect;
799      p.rect.setSize (QSize(option.rect.width()-2, option.rect.height()-8));
800      p.rect.moveCenter (option.rect.center());
801      p.fontMetrics = QApplication::fontMetrics();
802      p.minimum = 0;
803      p.maximum = 100;
804      p.textAlignment = Qt::AlignCenter;
805      p.textVisible = true;
806      p.progress = (int)(100.0*index.data().toDouble());
807      p.text = QString().sprintf("%d%%", p.progress);
808      style->drawControl(QStyle::CE_ProgressBar, &p, painter);
809    }
810  else if(column == COL_WANTED)
811    {
812      QStyleOptionButton o;
813      o.state = option.state;
814      o.direction = QApplication::layoutDirection();
815      o.rect.setSize (QSize(20, option.rect.height()));
816      o.rect.moveCenter (option.rect.center());
817      o.fontMetrics = QApplication::fontMetrics();
818      switch (index.data().toInt())
819        {
820          case Qt::Unchecked: o.state |= QStyle::State_Off; break;
821          case Qt::Checked:   o.state |= QStyle::State_On; break;
822          default:            o.state |= QStyle::State_NoChange;break;
823        }
824      style->drawControl (QStyle::CE_CheckBox, &o, painter);
825    }
826
827  painter->restore();
828}
829
830/****
831*****
832*****
833*****
834****/
835
836FileTreeView :: FileTreeView (QWidget * parent, bool isEditable):
837  QTreeView (parent),
838  myModel (this, isEditable),
839  myProxy (new QSortFilterProxyModel()),
840  myDelegate (this)
841{
842  setSortingEnabled (true);
843  setAlternatingRowColors (true);
844  setSelectionBehavior (QAbstractItemView::SelectRows);
845  setSelectionMode (QAbstractItemView::ExtendedSelection);
846  myProxy->setSourceModel (&myModel);
847  setModel (myProxy);
848  setItemDelegate (&myDelegate);
849  setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
850  sortByColumn (COL_NAME, Qt::AscendingOrder);
851  installEventFilter (this);
852
853  for (int i=0; i<FIRST_VISIBLE_COLUMN; ++i)
854    hideColumn (i);
855  for (int i=LAST_VISIBLE_COLUMN+1; i<NUM_COLUMNS; ++i)
856    hideColumn (i);
857
858  for (int i=FIRST_VISIBLE_COLUMN; i<=LAST_VISIBLE_COLUMN; ++i)
859    header()->setResizeMode(i, QHeaderView::Interactive);
860
861  connect (this, SIGNAL(clicked(const QModelIndex&)),
862           this, SLOT(onClicked(const QModelIndex&)));
863
864  connect (&myModel, SIGNAL(priorityChanged(const QSet<int>&, int)),
865           this,     SIGNAL(priorityChanged(const QSet<int>&, int)));
866
867  connect (&myModel, SIGNAL(wantedChanged(const QSet<int>&, bool)),
868           this,     SIGNAL(wantedChanged(const QSet<int>&, bool)));
869
870  connect (&myModel, SIGNAL(pathEdited(const QString&, const QString&)),
871           this,     SIGNAL(pathEdited(const QString&, const QString&)));
872}
873
874FileTreeView :: ~FileTreeView ()
875{
876  myProxy->deleteLater();
877}
878
879void
880FileTreeView :: onClicked (const QModelIndex& proxyIndex)
881{
882  const QModelIndex modelIndex = myProxy->mapToSource (proxyIndex);
883  myModel.clicked (modelIndex);
884}
885
886bool
887FileTreeView :: eventFilter (QObject * o, QEvent * event)
888{
889  // this is kind of a hack to get the last three columns be the
890  // right size, and to have the filename column use whatever
891  // space is left over...
892  if ((o == this) && (event->type() == QEvent::Resize))
893    {
894      QResizeEvent * r = dynamic_cast<QResizeEvent*>(event);
895      int left = r->size().width();
896      const QFontMetrics fontMetrics(font());
897      for (int column=FIRST_VISIBLE_COLUMN; column<=LAST_VISIBLE_COLUMN; ++column)
898        {
899          if (column == COL_NAME)
900            continue;
901          if (isColumnHidden (column))
902            continue;
903
904          const QString header = myModel.headerData (column, Qt::Horizontal).toString() + "    ";
905          const int width = fontMetrics.size (0, header).width();
906          setColumnWidth (column, width);
907            left -= width;
908        }
909      left -= 20; // not sure why this is necessary.  it works in different themes + font sizes though...
910      setColumnWidth(COL_NAME, std::max(left,0));
911    }
912
913  return false;
914}
915
916void
917FileTreeView :: update (const FileList& files, bool updateFields)
918{
919  foreach (const TrFile file, files)
920    {
921      QList<QModelIndex> added;
922      myModel.addFile (file.index, file.filename, file.wanted, file.priority, file.size, file.have, added, updateFields);
923      foreach (QModelIndex i, added)
924        expand (myProxy->mapFromSource(i));
925    }
926}
927
928void
929FileTreeView :: clear ()
930{
931  myModel.clear();
932}
Note: See TracBrowser for help on using the repository browser.