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

Last change on this file since 13893 was 13893, checked in by jordan, 8 years ago

(qt) #5252: disable file editing in the options dialog. remove keyboard shortcuts that conflicted with renaming files in file-tree.c. fix refresh issue in the file-tree when renaming files.

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