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

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

revert quint64/quint32/qint64/qint32 use to inttypes to match libtransmission's API

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