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

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

(qt) #5252 'file-renaming issues in Qt client': fix renaming flicker error reported by rb07

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