Changeset 13943


Ignore:
Timestamp:
Feb 3, 2013, 7:13:04 PM (8 years ago)
Author:
jordan
Message:

(qt) copyediting: whitespace/indentation

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/qt/details.cc

    r13940 r13943  
    6969namespace
    7070{
    71     const int REFRESH_INTERVAL_MSEC = 4000;
    72 
    73     const char * PREF_KEY ("pref-key");
    74 
    75     enum // peer columns
    76     {
    77         COL_LOCK,
    78         COL_UP,
    79         COL_DOWN,
    80         COL_PERCENT,
    81         COL_STATUS,
    82         COL_ADDRESS,
    83         COL_CLIENT,
    84         N_COLUMNS
    85     };
     71  const int REFRESH_INTERVAL_MSEC = 4000;
     72
     73  const char * PREF_KEY ("pref-key");
     74
     75  enum // peer columns
     76  {
     77    COL_LOCK,
     78    COL_UP,
     79    COL_DOWN,
     80    COL_PERCENT,
     81    COL_STATUS,
     82    COL_ADDRESS,
     83    COL_CLIENT,
     84    N_COLUMNS
     85  };
    8686}
    8787
     
    9292class PeerItem: public QTreeWidgetItem
    9393{
    94         Peer peer;
    95         QString collatedAddress;
    96         QString status;
    97 
    98     public:
    99         virtual ~PeerItem () { }
    100         PeerItem (const Peer& p) {
    101             peer = p;
    102             int q[4];
    103             if (sscanf (p.address.toUtf8 ().constData (), "%d.%d.%d.%d", q+0, q+1, q+2, q+3) == 4)
    104                 collatedAddress.sprintf ("%03d.%03d.%03d.%03d", q[0], q[1], q[2], q[3]);
    105             else
    106                 collatedAddress = p.address;
    107         }
    108     public:
    109         void refresh (const Peer& p) { peer = p; }
    110         void setStatus (const QString& s) { status = s; }
    111         virtual bool operator< (const QTreeWidgetItem & other) const {
    112             const PeerItem * i = dynamic_cast<const PeerItem*> (&other);
    113             QTreeWidget * tw (treeWidget ());
    114             const int column = tw ? tw->sortColumn () : 0;
    115             switch (column) {
    116                 case COL_UP: return peer.rateToPeer < i->peer.rateToPeer;
    117                 case COL_DOWN: return peer.rateToClient < i->peer.rateToClient;
    118                 case COL_PERCENT: return peer.progress < i->peer.progress;
    119                 case COL_STATUS: return status < i->status;
    120                 case COL_CLIENT: return peer.clientName < i->peer.clientName;
    121                 case COL_LOCK: return peer.isEncrypted && !i->peer.isEncrypted;
    122                 default: return collatedAddress < i->collatedAddress;
    123             }
    124         }
     94    Peer peer;
     95    QString collatedAddress;
     96    QString status;
     97
     98  public:
     99
     100    virtual ~PeerItem () {}
     101
     102    PeerItem (const Peer& p)
     103    {
     104      peer = p;
     105      int q[4];
     106      if (sscanf (p.address.toUtf8 ().constData (), "%d.%d.%d.%d", q+0, q+1, q+2, q+3) == 4)
     107        collatedAddress.sprintf ("%03d.%03d.%03d.%03d", q[0], q[1], q[2], q[3]);
     108      else
     109        collatedAddress = p.address;
     110    }
     111
     112  public:
     113
     114    void refresh (const Peer& p) { peer = p; }
     115
     116    void setStatus (const QString& s) { status = s; }
     117
     118    virtual bool operator< (const QTreeWidgetItem & other) const
     119    {
     120      const PeerItem * i = dynamic_cast<const PeerItem*> (&other);
     121      QTreeWidget * tw (treeWidget ());
     122      const int column = tw ? tw->sortColumn () : 0;
     123      switch (column)
     124        {
     125          case COL_UP: return peer.rateToPeer < i->peer.rateToPeer;
     126          case COL_DOWN: return peer.rateToClient < i->peer.rateToClient;
     127          case COL_PERCENT: return peer.progress < i->peer.progress;
     128          case COL_STATUS: return status < i->status;
     129          case COL_CLIENT: return peer.clientName < i->peer.clientName;
     130          case COL_LOCK: return peer.isEncrypted && !i->peer.isEncrypted;
     131          default: return collatedAddress < i->collatedAddress;
     132        }
     133    }
    125134};
    126135
     
    132141Details :: getStockIcon (const QString& freedesktop_name, int fallback)
    133142{
    134     QIcon icon = QIcon::fromTheme (freedesktop_name);
    135 
    136     if (icon.isNull ())
    137         icon = style ()->standardIcon (QStyle::StandardPixmap (fallback), 0, this);
    138 
    139     return icon;
    140 }
    141 
    142 Details :: Details (Session& session, Prefs& prefs, TorrentModel& model, QWidget * parent):
    143     QDialog (parent, Qt::Dialog),
    144     mySession (session),
    145     myPrefs (prefs),
    146     myModel (model),
    147     myChangedTorrents (false),
    148     myHavePendingRefresh (false)
    149 {
    150     QVBoxLayout * layout = new QVBoxLayout (this);
    151 
    152     setWindowTitle (tr ("Torrent Properties"));
    153 
    154     QTabWidget * t = new QTabWidget (this);
    155     QWidget * w;
    156     t->addTab (w = createInfoTab (),      tr ("Information"));
    157     myWidgets << w;
    158     t->addTab (w = createPeersTab (),     tr ("Peers"));
    159     myWidgets << w;
    160     t->addTab (w = createTrackerTab (),   tr ("Tracker"));
    161     myWidgets << w;
    162     t->addTab (w = createFilesTab (),     tr ("Files"));
    163     myWidgets << w;
    164     t->addTab (w = createOptionsTab (),   tr ("Options"));
    165     myWidgets << w;
    166     layout->addWidget (t);
    167 
    168     QDialogButtonBox * buttons = new QDialogButtonBox (QDialogButtonBox::Close, Qt::Horizontal, this);
    169     connect (buttons, SIGNAL (rejected ()), this, SLOT (close ()));
    170     layout->addWidget (buttons);
    171     QWidget::setAttribute (Qt::WA_DeleteOnClose, true);
    172 
    173     QList<int> initKeys;
    174     initKeys << Prefs :: SHOW_TRACKER_SCRAPES
    175              << Prefs :: SHOW_BACKUP_TRACKERS;
    176     foreach (int key, initKeys)
    177         refreshPref (key);
    178 
    179     connect (&myTimer, SIGNAL (timeout ()), this, SLOT (onTimer ()));
    180     connect (&myPrefs, SIGNAL (changed (int)), this, SLOT (refreshPref (int)));
    181 
    182     onTimer ();
    183     myTimer.setSingleShot (false);
    184     myTimer.start (REFRESH_INTERVAL_MSEC);
     143  QIcon icon = QIcon::fromTheme (freedesktop_name);
     144
     145  if (icon.isNull ())
     146    icon = style ()->standardIcon (QStyle::StandardPixmap (fallback), 0, this);
     147
     148  return icon;
     149}
     150
     151Details :: Details (Session       & session,
     152                    Prefs         & prefs,
     153                    TorrentModel  & model,
     154                    QWidget       * parent):
     155  QDialog (parent, Qt::Dialog),
     156  mySession (session),
     157  myPrefs (prefs),
     158  myModel (model),
     159  myChangedTorrents (false),
     160  myHavePendingRefresh (false)
     161{
     162  QVBoxLayout * layout = new QVBoxLayout (this);
     163
     164  setWindowTitle (tr ("Torrent Properties"));
     165
     166  QTabWidget * t = new QTabWidget (this);
     167  QWidget * w;
     168  t->addTab (w = createInfoTab (),      tr ("Information"));
     169  myWidgets << w;
     170  t->addTab (w = createPeersTab (),     tr ("Peers"));
     171  myWidgets << w;
     172  t->addTab (w = createTrackerTab (),   tr ("Tracker"));
     173  myWidgets << w;
     174  t->addTab (w = createFilesTab (),     tr ("Files"));
     175  myWidgets << w;
     176  t->addTab (w = createOptionsTab (),   tr ("Options"));
     177  myWidgets << w;
     178  layout->addWidget (t);
     179
     180  QDialogButtonBox * buttons = new QDialogButtonBox (QDialogButtonBox::Close, Qt::Horizontal, this);
     181  connect (buttons, SIGNAL (rejected ()), this, SLOT (close ()));
     182  layout->addWidget (buttons);
     183  QWidget::setAttribute (Qt::WA_DeleteOnClose, true);
     184
     185  QList<int> initKeys;
     186  initKeys << Prefs :: SHOW_TRACKER_SCRAPES
     187           << Prefs :: SHOW_BACKUP_TRACKERS;
     188  foreach (int key, initKeys)
     189    refreshPref (key);
     190
     191  connect (&myTimer, SIGNAL (timeout ()), this, SLOT (onTimer ()));
     192  connect (&myPrefs, SIGNAL (changed (int)), this, SLOT (refreshPref (int)));
     193
     194  onTimer ();
     195  myTimer.setSingleShot (false);
     196  myTimer.start (REFRESH_INTERVAL_MSEC);
    185197}
    186198
    187199Details :: ~Details ()
    188200{
    189     myTrackerDelegate->deleteLater ();
    190     myTrackerFilter->deleteLater ();
    191     myTrackerModel->deleteLater ();
     201  myTrackerDelegate->deleteLater ();
     202  myTrackerFilter->deleteLater ();
     203  myTrackerModel->deleteLater ();
    192204}
    193205
     
    195207Details :: setIds (const QSet<int>& ids)
    196208{
    197     if (ids == myIds)
    198         return;
    199 
    200     myChangedTorrents = true;
    201 
    202     // stop listening to the old torrents
    203     foreach (int id, myIds) {
    204         const Torrent * tor = myModel.getTorrentFromId (id);
    205         if (tor)
    206             disconnect (tor, SIGNAL (torrentChanged (int)), this, SLOT (onTorrentChanged ()));
    207     }
    208 
    209     myFileTreeView->clear ();
    210     myIds = ids;
    211     myTrackerModel->refresh (myModel, myIds);
    212 
    213     // listen to the new torrents
    214     foreach (int id, myIds) {
    215         const Torrent * tor = myModel.getTorrentFromId (id);
    216         if (tor)
    217             connect (tor, SIGNAL (torrentChanged (int)), this, SLOT (onTorrentChanged ()));
    218     }
    219 
    220     foreach (QWidget * w, myWidgets)
    221         w->setEnabled (false);
    222 
    223     onTimer ();
     209  if (ids == myIds)
     210    return;
     211
     212  myChangedTorrents = true;
     213
     214  // stop listening to the old torrents
     215  foreach (int id, myIds)
     216    {
     217      const Torrent * tor = myModel.getTorrentFromId (id);
     218      if (tor)
     219        disconnect (tor, SIGNAL (torrentChanged (int)), this, SLOT (onTorrentChanged ()));
     220    }
     221
     222  myFileTreeView->clear ();
     223  myIds = ids;
     224  myTrackerModel->refresh (myModel, myIds);
     225
     226  // listen to the new torrents
     227  foreach (int id, myIds)
     228    {
     229      const Torrent * tor = myModel.getTorrentFromId (id);
     230      if (tor)
     231        connect (tor, SIGNAL (torrentChanged (int)), this, SLOT (onTorrentChanged ()));
     232    }
     233
     234  foreach (QWidget * w, myWidgets)
     235    w->setEnabled (false);
     236
     237  onTimer ();
    224238}
    225239
     
    227241Details :: refreshPref (int key)
    228242{
    229     QString str;
    230 
    231     switch (key)
    232     {
    233         case Prefs :: SHOW_TRACKER_SCRAPES: {
    234             QItemSelectionModel * selectionModel (myTrackerView->selectionModel ());
    235             const QItemSelection selection (selectionModel->selection ());
    236             const QModelIndex currentIndex (selectionModel->currentIndex ());
    237             myTrackerDelegate->setShowMore (myPrefs.getBool (key));
    238             selectionModel->clear ();
    239             myTrackerView->reset ();
    240             selectionModel->select (selection, QItemSelectionModel::Select);
    241             selectionModel->setCurrentIndex (currentIndex, QItemSelectionModel::NoUpdate);
    242             break;
    243         }
    244 
    245         case Prefs :: SHOW_BACKUP_TRACKERS:
    246             myTrackerFilter->setShowBackupTrackers (myPrefs.getBool (key));
    247             break;
    248 
    249         default:
    250             break;
     243  QString str;
     244
     245  switch (key)
     246    {
     247      case Prefs :: SHOW_TRACKER_SCRAPES:
     248        {
     249          QItemSelectionModel * selectionModel (myTrackerView->selectionModel ());
     250          const QItemSelection selection (selectionModel->selection ());
     251          const QModelIndex currentIndex (selectionModel->currentIndex ());
     252          myTrackerDelegate->setShowMore (myPrefs.getBool (key));
     253          selectionModel->clear ();
     254          myTrackerView->reset ();
     255          selectionModel->select (selection, QItemSelectionModel::Select);
     256          selectionModel->setCurrentIndex (currentIndex, QItemSelectionModel::NoUpdate);
     257          break;
     258        }
     259
     260      case Prefs :: SHOW_BACKUP_TRACKERS:
     261        myTrackerFilter->setShowBackupTrackers (myPrefs.getBool (key));
     262        break;
     263
     264      default:
     265        break;
    251266    }
    252267}
     
    260275Details :: timeToStringRounded (int seconds)
    261276{
    262     if (seconds > 60) seconds -= (seconds % 60);
    263     return Formatter::timeToString (seconds);
     277  if (seconds > 60)
     278    seconds -= (seconds % 60);
     279
     280  return Formatter::timeToString (seconds);
    264281}
    265282
     
    267284Details :: onTimer ()
    268285{
    269     getNewData ();
     286  getNewData ();
    270287}
    271288
     
    273290Details :: getNewData ()
    274291{
    275     if (!myIds.empty ())
    276     {
    277         QSet<int> infos;
    278         foreach (int id, myIds) {
    279             const Torrent * tor = myModel.getTorrentFromId (id);
    280             if (tor->isMagnet ())
    281                 infos.insert (tor->id ());
    282         }
    283         if (!infos.isEmpty ())
    284             mySession.initTorrents (infos);
    285         mySession.refreshExtraStats (myIds);
     292  if (!myIds.empty ())
     293    {
     294      QSet<int> infos;
     295      foreach (int id, myIds)
     296        {
     297          const Torrent * tor = myModel.getTorrentFromId (id);
     298          if (tor->isMagnet ())
     299            infos.insert (tor->id ());
     300        }
     301
     302      if (!infos.isEmpty ())
     303        mySession.initTorrents (infos);
     304      mySession.refreshExtraStats (myIds);
    286305    }
    287306}
     
    290309Details :: onTorrentChanged ()
    291310{
    292     if (!myHavePendingRefresh) {
    293         myHavePendingRefresh = true;
    294         QTimer::singleShot (100, this, SLOT (refresh ()));
     311  if (!myHavePendingRefresh)
     312    {
     313      myHavePendingRefresh = true;
     314      QTimer::singleShot (100, this, SLOT (refresh ()));
    295315    }
    296316}
     
    298318namespace
    299319{
    300     void setIfIdle (QComboBox * box, int i)
    301     {
    302         if (!box->hasFocus ())
    303         {
    304             box->blockSignals (true);
    305             box->setCurrentIndex (i);
    306             box->blockSignals (false);
    307         }
    308     }
    309 
    310     void setIfIdle (QDoubleSpinBox * spin, double value)
    311     {
    312         if (!spin->hasFocus ())
    313         {
    314             spin->blockSignals (true);
    315             spin->setValue (value);
    316             spin->blockSignals (false);
    317         }
    318     }
    319 
    320     void setIfIdle (QSpinBox * spin, int value)
    321     {
    322         if (!spin->hasFocus ())
    323         {
    324             spin->blockSignals (true);
    325             spin->setValue (value);
    326             spin->blockSignals (false);
    327         }
    328     }
     320  void setIfIdle (QComboBox * box, int i)
     321  {
     322    if (!box->hasFocus ())
     323      {
     324        box->blockSignals (true);
     325        box->setCurrentIndex (i);
     326        box->blockSignals (false);
     327      }
     328  }
     329
     330  void setIfIdle (QDoubleSpinBox * spin, double value)
     331  {
     332    if (!spin->hasFocus ())
     333      {
     334        spin->blockSignals (true);
     335        spin->setValue (value);
     336        spin->blockSignals (false);
     337      }
     338  }
     339
     340  void setIfIdle (QSpinBox * spin, int value)
     341  {
     342    if (!spin->hasFocus ())
     343      {
     344        spin->blockSignals (true);
     345        spin->setValue (value);
     346        spin->blockSignals (false);
     347      }
     348  }
    329349}
    330350
     
    332352Details :: refresh ()
    333353{
    334     const int n = myIds.size ();
    335     const bool single = n == 1;
    336     const QString blank;
    337     const QFontMetrics fm (fontMetrics ());
    338     QList<const Torrent*> torrents;
    339     QString string;
    340     const QString none = tr ("None");
    341     const QString mixed = tr ("Mixed");
    342     const QString unknown = tr ("Unknown");
    343 
    344     // build a list of torrents
    345     foreach (int id, myIds) {
    346         const Torrent * tor = myModel.getTorrentFromId (id);
    347         if (tor)
    348             torrents << tor;
    349     }
    350 
    351     ///
    352     ///  activity tab
    353     ///
    354 
    355     // myStateLabel
    356     if (torrents.empty ())
     354  const int n = myIds.size ();
     355  const bool single = n == 1;
     356  const QString blank;
     357  const QFontMetrics fm (fontMetrics ());
     358  QList<const Torrent*> torrents;
     359  QString string;
     360  const QString none = tr ("None");
     361  const QString mixed = tr ("Mixed");
     362  const QString unknown = tr ("Unknown");
     363
     364  // build a list of torrents
     365  foreach (int id, myIds)
     366    {
     367      const Torrent * tor = myModel.getTorrentFromId (id);
     368      if (tor)
     369        torrents << tor;
     370    }
     371
     372  ///
     373  ///  activity tab
     374  ///
     375
     376  // myStateLabel
     377  if (torrents.empty ())
     378    {
     379      string = none;
     380    }
     381  else
     382    {
     383      bool isMixed = false;
     384      bool allPaused = true;
     385      bool allFinished = true;
     386      const tr_torrent_activity baseline = torrents[0]->getActivity ();
     387      foreach (const Torrent * t, torrents)
     388        {
     389          const tr_torrent_activity activity = t->getActivity ();
     390          if (activity != baseline)
     391            isMixed = true;
     392          if (activity != TR_STATUS_STOPPED)
     393            allPaused = allFinished = false;
     394          if (!t->isFinished ())
     395            allFinished = false;
     396        }
     397
     398      if (isMixed)
     399        string = mixed;
     400      else if (allFinished)
     401        string = tr ("Finished");
     402      else if (allPaused)
     403        string = tr ("Paused");
     404      else
     405        string = torrents[0]->activityString ();
     406    }
     407  myStateLabel->setText (string);
     408  const QString stateString = string;
     409
     410  // myHaveLabel
     411  double sizeWhenDone = 0;
     412  double leftUntilDone = 0;
     413  double available = 0;
     414  int64_t haveTotal = 0;
     415  int64_t haveVerified = 0;
     416  int64_t haveUnverified = 0;
     417  int64_t verifiedPieces = 0;
     418  if (torrents.empty ())
     419    {
     420      string = none;
     421    }
     422  else
     423    {
     424      foreach (const Torrent * t, torrents)
     425        {
     426          if (t->hasMetadata ())
     427            {
     428              haveTotal += t->haveTotal ();
     429              haveUnverified += t->haveUnverified ();
     430              const uint64_t v = t->haveVerified ();
     431              haveVerified += v;
     432              if (t->pieceSize ())
     433                verifiedPieces += v / t->pieceSize ();
     434              sizeWhenDone += t->sizeWhenDone ();
     435              leftUntilDone += t->leftUntilDone ();
     436              available += t->sizeWhenDone () - t->leftUntilDone () + t->desiredAvailable ();
     437            }
     438        }
     439
     440      const double d = 100.0 * (sizeWhenDone ? (sizeWhenDone - leftUntilDone) / sizeWhenDone : 1);
     441      QString pct = Formatter::percentToString (d);
     442
     443      if (!haveUnverified && !leftUntilDone)
     444        {
     445          string = tr ("%1 (100%)")
     446                     .arg (Formatter::sizeToString (haveVerified));
     447        }
     448      else if (!haveUnverified)
     449        {
     450          string = tr ("%1 of %2 (%3%)")
     451                     .arg (Formatter::sizeToString (haveVerified))
     452                     .arg (Formatter::sizeToString (sizeWhenDone))
     453                     .arg (pct);
     454        }
     455      else
     456        {
     457          string = tr ("%1 of %2 (%3%), %4 Unverified")
     458                     .arg (Formatter::sizeToString (haveVerified + haveUnverified))
     459                     .arg (Formatter::sizeToString (sizeWhenDone))
     460                     .arg (pct)
     461                     .arg (Formatter::sizeToString (haveUnverified));
     462        }
     463    }
     464  myHaveLabel->setText (string);
     465
     466  // myAvailabilityLabel
     467  if (torrents.empty ())
     468    string = none;
     469  else if (sizeWhenDone == 0)
     470    string = none;
     471  else
     472    string = QString ("%1%").arg (Formatter::percentToString ( (100.0 * available) / sizeWhenDone));
     473  myAvailabilityLabel->setText (string);
     474
     475  // myDownloadedLabel
     476  if (torrents.empty ())
     477    {
     478      string = none;
     479    }
     480  else
     481    {
     482      uint64_t d = 0;
     483      uint64_t f = 0;
     484      foreach (const Torrent * t, torrents)
     485        {
     486          d += t->downloadedEver ();
     487          f += t->failedEver ();
     488        }
     489      const QString dstr = Formatter::sizeToString (d);
     490      const QString fstr = Formatter::sizeToString (f);
     491      if (f)
     492        string = tr ("%1 (%2 corrupt)").arg (dstr).arg (fstr);
     493      else
     494        string = dstr;
     495    }
     496  myDownloadedLabel->setText (string);
     497
     498  //  myUploadedLabel
     499  if (torrents.empty ())
     500    {
     501      string = none;
     502    }
     503  else
     504    {
     505      uint64_t u = 0;
     506      uint64_t d = 0;
     507      foreach (const Torrent * t, torrents)
     508        {
     509          u += t->uploadedEver ();
     510          d += t->downloadedEver ();
     511        }
     512      string = tr ("%1 (Ratio: %2)")
     513                 .arg (Formatter::sizeToString (u))
     514                 .arg (Formatter::ratioToString (tr_getRatio (u, d)));
     515    }
     516  myUploadedLabel->setText (string);
     517
     518  const QDateTime qdt_now = QDateTime::currentDateTime ();
     519
     520  // myRunTimeLabel
     521  if (torrents.empty ())
     522    {
     523      string = none;
     524    }
     525  else
     526    {
     527      bool allPaused = true;
     528      QDateTime baseline = torrents[0]->lastStarted ();
     529      foreach (const Torrent * t, torrents)
     530        {
     531          if (baseline != t->lastStarted ())
     532            baseline = QDateTime ();
     533          if (!t->isPaused ())
     534            allPaused = false;
     535        }
     536
     537      if (allPaused)
     538        string = stateString; // paused || finished
     539      else if (baseline.isNull ())
     540        string = mixed;
     541      else
     542        string = Formatter::timeToString (baseline.secsTo (qdt_now));
     543    }
     544  myRunTimeLabel->setText (string);
     545
     546
     547  // myETALabel
     548  string.clear ();
     549  if (torrents.empty ())
     550    {
     551      string = none;
     552    }
     553  else
     554    {
     555      int baseline = torrents[0]->getETA ();
     556      foreach (const Torrent * t, torrents)
     557        {
     558          if (baseline != t->getETA ())
     559            {
     560              string = mixed;
     561              break;
     562            }
     563        }
     564
     565      if (string.isEmpty ())
     566        {
     567          if (baseline < 0)
     568            string = tr ("Unknown");
     569          else
     570            string = Formatter::timeToString (baseline);
     571       }
     572    }
     573  myETALabel->setText (string);
     574
     575
     576  // myLastActivityLabel
     577  if (torrents.empty ())
     578    {
     579      string = none;
     580    }
     581  else
     582    {
     583      QDateTime latest = torrents[0]->lastActivity ();
     584      foreach (const Torrent * t, torrents)
     585        {
     586          const QDateTime dt = t->lastActivity ();
     587          if (latest < dt)
     588            latest = dt;
     589        }
     590
     591      const int seconds = latest.isValid () ? latest.secsTo (qdt_now) : -1;
     592      if (seconds < 0)
    357593        string = none;
    358     else {
    359         bool isMixed = false;
    360         bool allPaused = true;
    361         bool allFinished = true;
    362         const tr_torrent_activity baseline = torrents[0]->getActivity ();
    363         foreach (const Torrent * t, torrents) {
    364             const tr_torrent_activity activity = t->getActivity ();
    365             if (activity != baseline)
    366                 isMixed = true;
    367             if (activity != TR_STATUS_STOPPED)
    368                 allPaused = allFinished = false;
    369             if (!t->isFinished ())
    370                 allFinished = false;
    371         }
    372         if (isMixed)
    373             string = mixed;
    374         else if (allFinished)
    375             string = tr ("Finished");
    376         else if (allPaused)
    377             string = tr ("Paused");
    378         else
    379             string = torrents[0]->activityString ();
    380     }
    381     myStateLabel->setText (string);
    382     const QString stateString = string;
    383 
    384     // myHaveLabel
    385     double sizeWhenDone = 0;
    386     double leftUntilDone = 0;
    387     double available = 0;
    388     int64_t haveTotal = 0;
    389     int64_t haveVerified = 0;
    390     int64_t haveUnverified = 0;
    391     int64_t verifiedPieces = 0;
    392     if (torrents.empty ())
     594      else if (seconds < 5)
     595        string = tr ("Active now");
     596      else
     597        string = tr ("%1 ago").arg (Formatter::timeToString (seconds));
     598    }
     599  myLastActivityLabel->setText (string);
     600
     601
     602  if (torrents.empty ())
     603    {
     604      string = none;
     605    }
     606  else
     607    {
     608      string = torrents[0]->getError ();
     609      foreach (const Torrent * t, torrents)
     610        {
     611          if (string != t->getError ())
     612            {
     613              string = mixed;
     614              break;
     615            }
     616        }
     617    }
     618  if (string.isEmpty ())
     619    string = none;
     620  myErrorLabel->setText (string);
     621
     622
     623  ///
     624  /// information tab
     625  ///
     626
     627  // mySizeLabel
     628  if (torrents.empty ())
     629    {
     630      string = none;
     631    }
     632  else
     633    {
     634      int pieces = 0;
     635      uint64_t size = 0;
     636      uint32_t pieceSize = torrents[0]->pieceSize ();
     637      foreach (const Torrent * t, torrents)
     638        {
     639          pieces += t->pieceCount ();
     640          size += t->totalSize ();
     641          if (pieceSize != t->pieceSize ())
     642            pieceSize = 0;
     643        }
     644
     645      if (!size)
    393646        string = none;
    394     else {
    395         foreach (const Torrent * t, torrents) {
    396             if (t->hasMetadata ()) {
    397                 haveTotal += t->haveTotal ();
    398                 haveUnverified += t->haveUnverified ();
    399                 const uint64_t v = t->haveVerified ();
    400                 haveVerified += v;
    401                 if (t->pieceSize ())
    402                     verifiedPieces += v / t->pieceSize ();
    403                 sizeWhenDone += t->sizeWhenDone ();
    404                 leftUntilDone += t->leftUntilDone ();
    405                 available += t->sizeWhenDone () - t->leftUntilDone () + t->desiredAvailable ();
     647      else if (pieceSize > 0)
     648        string = tr ("%1 (%Ln pieces @ %2)", "", pieces)
     649                   .arg (Formatter::sizeToString (size))
     650                   .arg (Formatter::memToString (pieceSize));
     651      else
     652        string = tr ("%1 (%Ln pieces)", "", pieces)
     653                   .arg (Formatter::sizeToString (size));
     654    }
     655  mySizeLabel->setText (string);
     656
     657  // myHashLabel
     658  string = none;
     659  if (!torrents.empty ())
     660    {
     661      string = torrents[0]->hashString ();
     662      foreach (const Torrent * t, torrents)
     663        {
     664          if (string != t->hashString ())
     665            {
     666              string = mixed;
     667              break;
    406668            }
    407669        }
    408         {
    409             const double d = 100.0 * (sizeWhenDone ? (sizeWhenDone - leftUntilDone) / sizeWhenDone : 1);
    410             QString pct = Formatter::percentToString (d);
    411 
    412             if (!haveUnverified && !leftUntilDone)
     670    }
     671  myHashLabel->setText (string);
     672
     673  // myPrivacyLabel
     674  string = none;
     675  if (!torrents.empty ())
     676    {
     677      bool b = torrents[0]->isPrivate ();
     678      string = b ? tr ("Private to this tracker -- DHT and PEX disabled")
     679                 : tr ("Public torrent");
     680      foreach (const Torrent * t, torrents)
     681        {
     682          if (b != t->isPrivate ())
    413683            {
    414                 string = tr ("%1 (100%)")
    415                              .arg (Formatter::sizeToString (haveVerified));
     684              string = mixed;
     685              break;
    416686            }
    417             else if (!haveUnverified)
     687        }
     688    }
     689  myPrivacyLabel->setText (string);
     690
     691  // myCommentBrowser
     692  string = none;
     693  if (!torrents.empty ())
     694    {
     695      string = torrents[0]->comment ();
     696      foreach (const Torrent * t, torrents)
     697        {
     698          if (string != t->comment ())
    418699            {
    419                 string = tr ("%1 of %2 (%3%)")
    420                              .arg (Formatter::sizeToString (haveVerified))
    421                              .arg (Formatter::sizeToString (sizeWhenDone))
    422                              .arg (pct);
     700              string = mixed;
     701              break;
    423702            }
    424             else
    425             {
    426                 string = tr ("%1 of %2 (%3%), %4 Unverified")
    427                              .arg (Formatter::sizeToString (haveVerified + haveUnverified))
    428                              .arg (Formatter::sizeToString (sizeWhenDone))
    429                              .arg (pct)
    430                              .arg (Formatter::sizeToString (haveUnverified));
    431             }
    432         }
    433     }
    434     myHaveLabel->setText (string);
    435 
    436     // myAvailabilityLabel
    437     if (torrents.empty ())
    438         string = none;
    439     else {
    440         if (sizeWhenDone == 0)
    441             string = none;
    442         else
    443             string = QString ("%1%").arg (Formatter::percentToString ( (100.0 * available) / sizeWhenDone));
    444     }
    445     myAvailabilityLabel->setText (string);
    446 
    447     // myDownloadedLabel
    448     if (torrents.empty ())
    449         string = none;
    450     else {
    451         uint64_t d = 0;
    452         uint64_t f = 0;
    453         foreach (const Torrent * t, torrents) {
    454             d += t->downloadedEver ();
    455             f += t->failedEver ();
    456         }
    457         const QString dstr = Formatter::sizeToString (d);
    458         const QString fstr = Formatter::sizeToString (f);
    459         if (f)
    460             string = tr ("%1 (%2 corrupt)").arg (dstr).arg (fstr);
    461         else
    462             string = dstr;
    463     }
    464     myDownloadedLabel->setText (string);
    465 
    466     if (torrents.empty ())
    467         string = none;
    468     else {
    469         uint64_t u = 0;
    470         uint64_t d = 0;
    471         foreach (const Torrent * t, torrents) {
    472             u += t->uploadedEver ();
    473             d += t->downloadedEver ();
    474         }
    475         string = tr ("%1 (Ratio: %2)")
    476                    .arg (Formatter::sizeToString (u))
    477                    .arg (Formatter::ratioToString (tr_getRatio (u, d)));
    478     }
    479     myUploadedLabel->setText (string);
    480 
    481     const QDateTime qdt_now = QDateTime::currentDateTime ();
    482 
    483     // myRunTimeLabel
    484     if (torrents.empty ())
    485         string = none;
    486     else {
    487         bool allPaused = true;
    488         QDateTime baseline = torrents[0]->lastStarted ();
    489         foreach (const Torrent * t, torrents) {
    490             if (baseline != t->lastStarted ())
    491                 baseline = QDateTime ();
    492             if (!t->isPaused ())
    493                 allPaused = false;
    494         }
    495         if (allPaused)
    496             string = stateString; // paused || finished
    497         else if (baseline.isNull ())
    498             string = mixed;
    499         else
    500             string = Formatter::timeToString (baseline.secsTo (qdt_now));
    501     }
    502     myRunTimeLabel->setText (string);
    503 
    504 
    505     // myETALabel
    506     string.clear ();
    507     if (torrents.empty ())
    508         string = none;
    509     else {
    510         int baseline = torrents[0]->getETA ();
    511         foreach (const Torrent * t, torrents) {
    512             if (baseline != t->getETA ()) {
    513                 string = mixed;
    514                 break;
    515             }
    516         }
    517         if (string.isEmpty ()) {
    518             if (baseline < 0)
    519                 string = tr ("Unknown");
    520             else
    521                 string = Formatter::timeToString (baseline);
    522        }
    523     }
    524     myETALabel->setText (string);
    525 
    526 
    527     // myLastActivityLabel
    528     if (torrents.empty ())
    529         string = none;
    530     else {
    531         QDateTime latest = torrents[0]->lastActivity ();
    532         foreach (const Torrent * t, torrents) {
    533             const QDateTime dt = t->lastActivity ();
    534             if (latest < dt)
    535                 latest = dt;
    536         }
    537         const int seconds = latest.isValid () ? latest.secsTo (qdt_now) : -1;
    538         if (seconds < 0)
    539             string = none;
    540         else if (seconds < 5)
    541             string = tr ("Active now");
    542         else
    543             string = tr ("%1 ago").arg (Formatter::timeToString (seconds));
    544     }
    545     myLastActivityLabel->setText (string);
    546 
    547 
    548     if (torrents.empty ())
    549         string = none;
    550     else {
    551         string = torrents[0]->getError ();
    552         foreach (const Torrent * t, torrents) {
    553             if (string != t->getError ()) {
    554                 string = mixed;
    555                 break;
    556             }
    557         }
    558     }
    559     if (string.isEmpty ())
    560         string = none;
    561     myErrorLabel->setText (string);
    562 
    563 
    564     ///
    565     /// information tab
    566     ///
    567 
    568     // mySizeLabel
    569     if (torrents.empty ())
    570         string = none;
    571     else {
    572         int pieces = 0;
    573         uint64_t size = 0;
    574         uint32_t pieceSize = torrents[0]->pieceSize ();
    575         foreach (const Torrent * t, torrents) {
    576             pieces += t->pieceCount ();
    577             size += t->totalSize ();
    578             if (pieceSize != t->pieceSize ())
    579                 pieceSize = 0;
    580         }
    581         if (!size)
    582             string = none;
    583         else if (pieceSize > 0)
    584             string = tr ("%1 (%Ln pieces @ %2)", "", pieces)
    585                      .arg (Formatter::sizeToString (size))
    586                      .arg (Formatter::memToString (pieceSize));
    587         else
    588             string = tr ("%1 (%Ln pieces)", "", pieces)
    589                      .arg (Formatter::sizeToString (size));
    590     }
    591     mySizeLabel->setText (string);
    592 
    593     // myHashLabel
    594     if (torrents.empty ())
    595         string = none;
    596     else {
    597         string = torrents[0]->hashString ();
    598         foreach (const Torrent * t, torrents) {
    599             if (string != t->hashString ()) {
    600                 string = mixed;
    601                 break;
    602             }
    603         }
    604     }
    605     myHashLabel->setText (string);
    606 
    607     // myPrivacyLabel
    608     if (torrents.empty ())
    609         string = none;
    610     else {
    611         bool b = torrents[0]->isPrivate ();
    612         string = b ? tr ("Private to this tracker -- DHT and PEX disabled")
    613                    : tr ("Public torrent");
    614         foreach (const Torrent * t, torrents) {
    615             if (b != t->isPrivate ()) {
    616                 string = mixed;
    617                 break;
    618             }
    619         }
    620     }
    621     myPrivacyLabel->setText (string);
    622 
    623     // myCommentBrowser
    624     if (torrents.empty ())
    625         string = none;
    626     else {
    627         string = torrents[0]->comment ();
    628         foreach (const Torrent * t, torrents) {
    629             if (string != t->comment ()) {
    630                 string = mixed;
    631                 break;
    632             }
    633         }
    634     }
    635     if (myCommentBrowser->toPlainText() != string) {
     703        }
     704    }
     705  if (myCommentBrowser->toPlainText() != string)
     706    {
    636707      myCommentBrowser->setText (string);
    637708      myCommentBrowser->setMaximumHeight (QWIDGETSIZE_MAX);
    638709    }
    639710
    640     // myOriginLabel
    641     if (torrents.empty ())
    642         string = none;
    643     else {
    644         bool mixed_creator=false, mixed_date=false;
    645         const QString creator = torrents[0]->creator ();
    646         const QString date = torrents[0]->dateCreated ().toString ();
    647         foreach (const Torrent * t, torrents) {
    648             mixed_creator |= (creator != t->creator ());
    649             mixed_date |= (date != t->dateCreated ().toString ());
    650         }
    651         if (mixed_creator && mixed_date)
    652             string = mixed;
    653         else if (mixed_date && !creator.isEmpty ())
    654             string = tr ("Created by %1").arg (creator);
    655         else if (mixed_creator && !date.isEmpty ())
    656             string = tr ("Created on %1").arg (date);
    657         else if (creator.isEmpty () && date.isEmpty ())
    658             string = tr ("N/A");
    659         else
    660             string = tr ("Created by %1 on %2").arg (creator).arg (date);
    661     }
    662     myOriginLabel->setText (string);
    663 
    664     // myLocationLabel
    665     if (torrents.empty ())
    666         string = none;
    667     else {
    668         string = torrents[0]->getPath ();
    669         foreach (const Torrent * t, torrents) {
    670             if (string != t->getPath ()) {
    671                 string = mixed;
    672                 break;
     711  // myOriginLabel
     712  string = none;
     713  if (!torrents.empty ())
     714    {
     715      bool mixed_creator=false, mixed_date=false;
     716      const QString creator = torrents[0]->creator ();
     717      const QString date = torrents[0]->dateCreated ().toString ();
     718      foreach (const Torrent * t, torrents)
     719        {
     720          mixed_creator |= (creator != t->creator ());
     721          mixed_date |= (date != t->dateCreated ().toString ());
     722        }
     723
     724      if (mixed_creator && mixed_date)
     725        string = mixed;
     726      else if (mixed_date && !creator.isEmpty ())
     727        string = tr ("Created by %1").arg (creator);
     728      else if (mixed_creator && !date.isEmpty ())
     729        string = tr ("Created on %1").arg (date);
     730      else if (creator.isEmpty () && date.isEmpty ())
     731        string = tr ("N/A");
     732      else
     733        string = tr ("Created by %1 on %2").arg (creator).arg (date);
     734    }
     735  myOriginLabel->setText (string);
     736
     737  // myLocationLabel
     738  string = none;
     739  if (!torrents.empty ())
     740    {
     741      string = torrents[0]->getPath ();
     742      foreach (const Torrent * t, torrents)
     743        {
     744          if (string != t->getPath ())
     745            {
     746              string = mixed;
     747              break;
    673748            }
    674749        }
    675750    }
    676     myLocationLabel->setText (string);
    677 
    678 
    679     ///
    680     ///  Options Tab
    681     ///
    682 
    683     if (myChangedTorrents && !torrents.empty ())
    684     {
    685         int i;
    686         const Torrent * baseline = *torrents.begin ();
    687         const Torrent * tor;
    688         bool uniform;
    689         bool baselineFlag;
    690         int baselineInt;
    691 
    692         // mySessionLimitCheck
    693         uniform = true;
    694         baselineFlag = baseline->honorsSessionLimits ();
    695         foreach (tor, torrents) if (baselineFlag != tor->honorsSessionLimits ()) { uniform = false; break; }
    696         mySessionLimitCheck->setChecked (uniform && baselineFlag);
    697 
    698         // mySingleDownCheck
    699         uniform = true;
    700         baselineFlag = baseline->downloadIsLimited ();
    701         foreach (tor, torrents) if (baselineFlag != tor->downloadIsLimited ()) { uniform = false; break; }
    702         mySingleDownCheck->setChecked (uniform && baselineFlag);
    703 
    704         // mySingleUpCheck
    705         uniform = true;
    706         baselineFlag = baseline->uploadIsLimited ();
    707         foreach (tor, torrents) if (baselineFlag != tor->uploadIsLimited ()) { uniform = false; break; }
    708         mySingleUpCheck->setChecked (uniform && baselineFlag);
    709 
    710         // myBandwidthPriorityCombo
    711         uniform = true;
    712         baselineInt = baseline->getBandwidthPriority ();
    713         foreach (tor, torrents) if (baselineInt != tor->getBandwidthPriority ()) { uniform = false; break; }
    714         if (uniform)
    715             i = myBandwidthPriorityCombo->findData (baselineInt);
    716         else
    717             i = -1;
    718         setIfIdle (myBandwidthPriorityCombo, i);
    719 
    720         setIfIdle (mySingleDownSpin, int (tor->downloadLimit ().KBps ()));
    721         setIfIdle (mySingleUpSpin, int (tor->uploadLimit ().KBps ()));
    722         setIfIdle (myPeerLimitSpin, tor->peerLimit ());
    723     }
    724 
    725     if (!torrents.empty ())
    726     {
    727         const Torrent * tor;
    728 
    729         // ratio
    730         bool uniform = true;
    731         int baselineInt = torrents[0]->seedRatioMode ();
    732         foreach (tor, torrents) if (baselineInt != tor->seedRatioMode ()) { uniform = false; break; }
    733 
    734         setIfIdle (myRatioCombo, uniform ? myRatioCombo->findData (baselineInt) : -1);
    735         myRatioSpin->setVisible (uniform && (baselineInt == TR_RATIOLIMIT_SINGLE));
    736 
    737         setIfIdle (myRatioSpin, tor->seedRatioLimit ());
    738 
    739         // idle
    740         uniform = true;
    741         baselineInt = torrents[0]->seedIdleMode ();
    742         foreach (tor, torrents) if (baselineInt != tor->seedIdleMode ()) { uniform = false; break; }
    743 
    744         setIfIdle (myIdleCombo, uniform ? myIdleCombo->findData (baselineInt) : -1);
    745         myIdleSpin->setVisible (uniform && (baselineInt == TR_RATIOLIMIT_SINGLE));
    746 
    747         setIfIdle (myIdleSpin, tor->seedIdleLimit ());
    748     }
    749 
    750     ///
    751     ///  Tracker tab
    752     ///
    753 
    754     myTrackerModel->refresh (myModel, myIds);
    755 
    756     ///
    757     ///  Peers tab
    758     ///
    759 
    760     QMap<QString,QTreeWidgetItem*> peers2;
    761     QList<QTreeWidgetItem*> newItems;
    762     foreach (const Torrent * t, torrents)
    763     {
    764         const QString idStr (QString::number (t->id ()));
    765         PeerList peers = t->peers ();
    766 
    767         foreach (const Peer& peer, peers)
    768         {
    769             const QString key = idStr + ":" + peer.address;
    770             PeerItem * item = (PeerItem*) myPeers.value (key, 0);
    771 
    772             if (item == 0) // new peer has connected
     751  myLocationLabel->setText (string);
     752
     753
     754  ///
     755  ///  Options Tab
     756  ///
     757
     758  if (myChangedTorrents && !torrents.empty ())
     759    {
     760      int i;
     761      bool uniform;
     762      bool baselineFlag;
     763      int baselineInt;
     764      const Torrent * tor;
     765      const Torrent * baseline = *torrents.begin ();
     766
     767      // mySessionLimitCheck
     768      uniform = true;
     769      baselineFlag = baseline->honorsSessionLimits ();
     770      foreach (tor, torrents) if (baselineFlag != tor->honorsSessionLimits ()) { uniform = false; break; }
     771      mySessionLimitCheck->setChecked (uniform && baselineFlag);
     772
     773      // mySingleDownCheck
     774      uniform = true;
     775      baselineFlag = baseline->downloadIsLimited ();
     776      foreach (tor, torrents) if (baselineFlag != tor->downloadIsLimited ()) { uniform = false; break; }
     777      mySingleDownCheck->setChecked (uniform && baselineFlag);
     778
     779      // mySingleUpCheck
     780      uniform = true;
     781      baselineFlag = baseline->uploadIsLimited ();
     782      foreach (tor, torrents) if (baselineFlag != tor->uploadIsLimited ()) { uniform = false; break; }
     783      mySingleUpCheck->setChecked (uniform && baselineFlag);
     784
     785      // myBandwidthPriorityCombo
     786      uniform = true;
     787      baselineInt = baseline->getBandwidthPriority ();
     788      foreach (tor, torrents) if (baselineInt != tor->getBandwidthPriority ()) { uniform = false; break; }
     789      if (uniform)
     790        i = myBandwidthPriorityCombo->findData (baselineInt);
     791      else
     792        i = -1;
     793      setIfIdle (myBandwidthPriorityCombo, i);
     794
     795      setIfIdle (mySingleDownSpin, int (tor->downloadLimit ().KBps ()));
     796      setIfIdle (mySingleUpSpin, int (tor->uploadLimit ().KBps ()));
     797      setIfIdle (myPeerLimitSpin, tor->peerLimit ());
     798    }
     799
     800  if (!torrents.empty ())
     801    {
     802      const Torrent * tor;
     803
     804      // ratio
     805      bool uniform = true;
     806      int baselineInt = torrents[0]->seedRatioMode ();
     807      foreach (tor, torrents) if (baselineInt != tor->seedRatioMode ()) { uniform = false; break; }
     808
     809      setIfIdle (myRatioCombo, uniform ? myRatioCombo->findData (baselineInt) : -1);
     810      myRatioSpin->setVisible (uniform && (baselineInt == TR_RATIOLIMIT_SINGLE));
     811
     812      setIfIdle (myRatioSpin, tor->seedRatioLimit ());
     813
     814      // idle
     815      uniform = true;
     816      baselineInt = torrents[0]->seedIdleMode ();
     817      foreach (tor, torrents) if (baselineInt != tor->seedIdleMode ()) { uniform = false; break; }
     818
     819      setIfIdle (myIdleCombo, uniform ? myIdleCombo->findData (baselineInt) : -1);
     820      myIdleSpin->setVisible (uniform && (baselineInt == TR_RATIOLIMIT_SINGLE));
     821
     822      setIfIdle (myIdleSpin, tor->seedIdleLimit ());
     823    }
     824
     825  ///
     826  ///  Tracker tab
     827  ///
     828
     829  myTrackerModel->refresh (myModel, myIds);
     830
     831  ///
     832  ///  Peers tab
     833  ///
     834
     835  QMap<QString,QTreeWidgetItem*> peers2;
     836  QList<QTreeWidgetItem*> newItems;
     837  foreach (const Torrent * t, torrents)
     838    {
     839      const QString idStr (QString::number (t->id ()));
     840      PeerList peers = t->peers ();
     841
     842      foreach (const Peer& peer, peers)
     843        {
     844          const QString key = idStr + ":" + peer.address;
     845          PeerItem * item = (PeerItem*) myPeers.value (key, 0);
     846
     847          if (item == 0) // new peer has connected
    773848            {
    774                 static const QIcon myEncryptionIcon (":/icons/encrypted.png");
    775                 static const QIcon myEmptyIcon;
    776                 item = new PeerItem (peer);
    777                 item->setTextAlignment (COL_UP, Qt::AlignRight|Qt::AlignVCenter);
    778                 item->setTextAlignment (COL_DOWN, Qt::AlignRight|Qt::AlignVCenter);
    779                 item->setTextAlignment (COL_PERCENT, Qt::AlignRight|Qt::AlignVCenter);
    780                 item->setIcon (COL_LOCK, peer.isEncrypted ? myEncryptionIcon : myEmptyIcon);
    781                 item->setToolTip (COL_LOCK, peer.isEncrypted ? tr ("Encrypted connection") : "");
    782                 item->setText (COL_ADDRESS, peer.address);
    783                 item->setText (COL_CLIENT, peer.clientName);
    784                 newItems << item;
     849              static const QIcon myEncryptionIcon (":/icons/encrypted.png");
     850              static const QIcon myEmptyIcon;
     851              item = new PeerItem (peer);
     852              item->setTextAlignment (COL_UP, Qt::AlignRight|Qt::AlignVCenter);
     853              item->setTextAlignment (COL_DOWN, Qt::AlignRight|Qt::AlignVCenter);
     854              item->setTextAlignment (COL_PERCENT, Qt::AlignRight|Qt::AlignVCenter);
     855              item->setIcon (COL_LOCK, peer.isEncrypted ? myEncryptionIcon : myEmptyIcon);
     856              item->setToolTip (COL_LOCK, peer.isEncrypted ? tr ("Encrypted connection") : "");
     857              item->setText (COL_ADDRESS, peer.address);
     858              item->setText (COL_CLIENT, peer.clientName);
     859              newItems << item;
    785860            }
    786861
    787             const QString code = peer.flagStr;
    788             item->setStatus (code);
    789             item->refresh (peer);
    790 
    791             QString codeTip;
    792             foreach (QChar ch, code) {
    793                 QString txt;
    794                 switch (ch.toAscii ()) {
    795                     case 'O': txt = tr ("Optimistic unchoke"); break;
    796                     case 'D': txt = tr ("Downloading from this peer"); break;
    797                     case 'd': txt = tr ("We would download from this peer if they would let us"); break;
    798                     case 'U': txt = tr ("Uploading to peer"); break;
    799                     case 'u': txt = tr ("We would upload to this peer if they asked"); break;
    800                     case 'K': txt = tr ("Peer has unchoked us, but we're not interested"); break;
    801                     case '?': txt = tr ("We unchoked this peer, but they're not interested"); break;
    802                     case 'E': txt = tr ("Encrypted connection"); break;
    803                     case 'H': txt = tr ("Peer was discovered through DHT"); break;
    804                     case 'X': txt = tr ("Peer was discovered through Peer Exchange (PEX)"); break;
    805                     case 'I': txt = tr ("Peer is an incoming connection"); break;
    806                     case 'T': txt = tr ("Peer is connected over uTP"); break;
     862          const QString code = peer.flagStr;
     863          item->setStatus (code);
     864          item->refresh (peer);
     865
     866          QString codeTip;
     867          foreach (QChar ch, code)
     868            {
     869              QString txt;
     870              switch (ch.toAscii ())
     871                {
     872                  case 'O': txt = tr ("Optimistic unchoke"); break;
     873                  case 'D': txt = tr ("Downloading from this peer"); break;
     874                  case 'd': txt = tr ("We would download from this peer if they would let us"); break;
     875                  case 'U': txt = tr ("Uploading to peer"); break;
     876                  case 'u': txt = tr ("We would upload to this peer if they asked"); break;
     877                  case 'K': txt = tr ("Peer has unchoked us, but we're not interested"); break;
     878                  case '?': txt = tr ("We unchoked this peer, but they're not interested"); break;
     879                  case 'E': txt = tr ("Encrypted connection"); break;
     880                  case 'H': txt = tr ("Peer was discovered through DHT"); break;
     881                  case 'X': txt = tr ("Peer was discovered through Peer Exchange (PEX)"); break;
     882                  case 'I': txt = tr ("Peer is an incoming connection"); break;
     883                  case 'T': txt = tr ("Peer is connected over uTP"); break;
    807884                }
    808                 if (!txt.isEmpty ())
    809                     codeTip += QString ("%1: %2\n").arg (ch).arg (txt);
     885
     886              if (!txt.isEmpty ())
     887                codeTip += QString ("%1: %2\n").arg (ch).arg (txt);
    810888            }
    811889
    812             if (!codeTip.isEmpty ())
    813                 codeTip.resize (codeTip.size ()-1); // eat the trailing linefeed
    814 
    815             item->setText (COL_UP, peer.rateToPeer.isZero () ? "" : Formatter::speedToString (peer.rateToPeer));
    816             item->setText (COL_DOWN, peer.rateToClient.isZero () ? "" : Formatter::speedToString (peer.rateToClient));
    817             item->setText (COL_PERCENT, peer.progress > 0 ? QString ("%1%").arg ( (int) (peer.progress * 100.0)) : "");
    818             item->setText (COL_STATUS, code);
    819             item->setToolTip (COL_STATUS, codeTip);
    820 
    821             peers2.insert (key, item);
    822         }
    823     }
    824     myPeerTree->addTopLevelItems (newItems);
    825     foreach (QString key, myPeers.keys ()) {
    826         if (!peers2.contains (key)) { // old peer has disconnected
    827             QTreeWidgetItem * item = myPeers.value (key, 0);
    828             myPeerTree->takeTopLevelItem (myPeerTree->indexOfTopLevelItem (item));
    829             delete item;
    830         }
    831     }
    832     myPeers = peers2;
    833 
    834     if (!single)
    835         myFileTreeView->clear ();
    836     if (single)
    837         myFileTreeView->update (torrents[0]->files (), myChangedTorrents);
    838 
    839     myChangedTorrents = false;
    840     myHavePendingRefresh = false;
    841     foreach (QWidget * w, myWidgets)
    842         w->setEnabled (true);
     890          if (!codeTip.isEmpty ())
     891            codeTip.resize (codeTip.size ()-1); // eat the trailing linefeed
     892
     893          item->setText (COL_UP, peer.rateToPeer.isZero () ? "" : Formatter::speedToString (peer.rateToPeer));
     894          item->setText (COL_DOWN, peer.rateToClient.isZero () ? "" : Formatter::speedToString (peer.rateToClient));
     895          item->setText (COL_PERCENT, peer.progress > 0 ? QString ("%1%").arg ( (int) (peer.progress * 100.0)) : "");
     896          item->setText (COL_STATUS, code);
     897          item->setToolTip (COL_STATUS, codeTip);
     898
     899          peers2.insert (key, item);
     900        }
     901    }
     902
     903  myPeerTree->addTopLevelItems (newItems);
     904  foreach (QString key, myPeers.keys ())
     905    {
     906      if (!peers2.contains (key)) // old peer has disconnected
     907        {
     908          QTreeWidgetItem * item = myPeers.value (key, 0);
     909          myPeerTree->takeTopLevelItem (myPeerTree->indexOfTopLevelItem (item));
     910          delete item;
     911        }
     912    }
     913  myPeers = peers2;
     914
     915  if (!single)
     916    myFileTreeView->clear ();
     917  if (single)
     918    myFileTreeView->update (torrents[0]->files (), myChangedTorrents);
     919
     920  myChangedTorrents = false;
     921  myHavePendingRefresh = false;
     922  foreach (QWidget * w, myWidgets)
     923    w->setEnabled (true);
    843924}
    844925
     
    846927Details :: enableWhenChecked (QCheckBox * box, QWidget * w)
    847928{
    848     connect (box, SIGNAL (toggled (bool)), w, SLOT (setEnabled (bool)));
    849     w->setEnabled (box->isChecked ());
     929  connect (box, SIGNAL (toggled (bool)), w, SLOT (setEnabled (bool)));
     930  w->setEnabled (box->isChecked ());
    850931}
    851932
     
    858939Details :: createInfoTab ()
    859940{
    860     HIG * hig = new HIG (this);
    861 
    862     hig->addSectionTitle (tr ("Activity"));
    863     hig->addRow (tr ("Have:"), myHaveLabel = new SqueezeLabel);
    864     hig->addRow (tr ("Availability:"), myAvailabilityLabel = new SqueezeLabel);
    865     hig->addRow (tr ("Downloaded:"), myDownloadedLabel = new SqueezeLabel);
    866     hig->addRow (tr ("Uploaded:"), myUploadedLabel = new SqueezeLabel);
    867     hig->addRow (tr ("State:"), myStateLabel = new SqueezeLabel);
    868     hig->addRow (tr ("Running time:"), myRunTimeLabel = new SqueezeLabel);
    869     hig->addRow (tr ("Remaining time:"), myETALabel = new SqueezeLabel);
    870     hig->addRow (tr ("Last activity:"), myLastActivityLabel = new SqueezeLabel);
    871     hig->addRow (tr ("Error:"), myErrorLabel = new SqueezeLabel);
    872     hig->addSectionDivider ();
    873 
    874     hig->addSectionDivider ();
    875     hig->addSectionTitle (tr ("Details"));
    876     hig->addRow (tr ("Size:"), mySizeLabel = new SqueezeLabel);
    877     hig->addRow (tr ("Location:"), myLocationLabel = new SqueezeLabel);
    878     hig->addRow (tr ("Hash:"), myHashLabel = new SqueezeLabel);
    879     hig->addRow (tr ("Privacy:"), myPrivacyLabel = new SqueezeLabel);
    880     hig->addRow (tr ("Origin:"), myOriginLabel = new SqueezeLabel);
    881     myOriginLabel->setMinimumWidth (325); // stop long origin strings from resizing the widgit
    882     hig->addRow (tr ("Comment:"), myCommentBrowser = new QTextBrowser);
    883     const int h = QFontMetrics (myCommentBrowser->font ()).lineSpacing () * 4;
    884     myCommentBrowser->setFixedHeight (h);
    885 
    886     hig->finish ();
    887 
    888     return hig;
     941  HIG * hig = new HIG (this);
     942
     943  hig->addSectionTitle (tr ("Activity"));
     944  hig->addRow (tr ("Have:"), myHaveLabel = new SqueezeLabel);
     945  hig->addRow (tr ("Availability:"), myAvailabilityLabel = new SqueezeLabel);
     946  hig->addRow (tr ("Downloaded:"), myDownloadedLabel = new SqueezeLabel);
     947  hig->addRow (tr ("Uploaded:"), myUploadedLabel = new SqueezeLabel);
     948  hig->addRow (tr ("State:"), myStateLabel = new SqueezeLabel);
     949  hig->addRow (tr ("Running time:"), myRunTimeLabel = new SqueezeLabel);
     950  hig->addRow (tr ("Remaining time:"), myETALabel = new SqueezeLabel);
     951  hig->addRow (tr ("Last activity:"), myLastActivityLabel = new SqueezeLabel);
     952  hig->addRow (tr ("Error:"), myErrorLabel = new SqueezeLabel);
     953  hig->addSectionDivider ();
     954
     955  hig->addSectionDivider ();
     956  hig->addSectionTitle (tr ("Details"));
     957  hig->addRow (tr ("Size:"), mySizeLabel = new SqueezeLabel);
     958  hig->addRow (tr ("Location:"), myLocationLabel = new SqueezeLabel);
     959  hig->addRow (tr ("Hash:"), myHashLabel = new SqueezeLabel);
     960  hig->addRow (tr ("Privacy:"), myPrivacyLabel = new SqueezeLabel);
     961  hig->addRow (tr ("Origin:"), myOriginLabel = new SqueezeLabel);
     962  myOriginLabel->setMinimumWidth (325); // stop long origin strings from resizing the widgit
     963  hig->addRow (tr ("Comment:"), myCommentBrowser = new QTextBrowser);
     964  const int h = QFontMetrics (myCommentBrowser->font ()).lineSpacing () * 4;
     965  myCommentBrowser->setFixedHeight (h);
     966
     967  hig->finish ();
     968
     969  return hig;
    889970}
    890971
     
    896977Details :: onShowTrackerScrapesToggled (bool val)
    897978{
    898     myPrefs.set (Prefs::SHOW_TRACKER_SCRAPES, val);
     979  myPrefs.set (Prefs::SHOW_TRACKER_SCRAPES, val);
    899980}
    900981
     
    10481129Details :: onRemoveTrackerClicked ()
    10491130{
    1050     // make a map of torrentIds to announce URLs to remove
    1051     QItemSelectionModel * selectionModel = myTrackerView->selectionModel ();
    1052     QModelIndexList selectedRows = selectionModel->selectedRows ();
    1053     QMap<int,int> torrentId_to_trackerIds;
    1054     foreach (QModelIndex i, selectedRows)
    1055     {
    1056         const TrackerInfo inf = myTrackerView->model ()->data (i, TrackerModel::TrackerRole).value<TrackerInfo> ();
    1057         torrentId_to_trackerIds.insertMulti (inf.torrentId, inf.st.id);
    1058     }
    1059 
    1060     // batch all of a tracker's torrents into one command
    1061     foreach (int id, torrentId_to_trackerIds.uniqueKeys ())
    1062     {
    1063         QSet<int> ids;
    1064         ids << id;
    1065         mySession.torrentSet (ids, TR_KEY_trackerRemove, torrentId_to_trackerIds.values (id));
    1066     }
    1067 
    1068     selectionModel->clearSelection ();
    1069     getNewData ();
     1131  // make a map of torrentIds to announce URLs to remove
     1132  QItemSelectionModel * selectionModel = myTrackerView->selectionModel ();
     1133  QModelIndexList selectedRows = selectionModel->selectedRows ();
     1134  QMap<int,int> torrentId_to_trackerIds;
     1135  foreach (QModelIndex i, selectedRows)
     1136    {
     1137      const TrackerInfo inf = myTrackerView->model ()->data (i, TrackerModel::TrackerRole).value<TrackerInfo> ();
     1138      torrentId_to_trackerIds.insertMulti (inf.torrentId, inf.st.id);
     1139    }
     1140
     1141  // batch all of a tracker's torrents into one command
     1142  foreach (int id, torrentId_to_trackerIds.uniqueKeys ())
     1143    {
     1144      QSet<int> ids;
     1145      ids << id;
     1146      mySession.torrentSet (ids, TR_KEY_trackerRemove, torrentId_to_trackerIds.values (id));
     1147    }
     1148
     1149  selectionModel->clearSelection ();
     1150  getNewData ();
    10701151}
    10711152
     
    10731154Details :: createOptionsTab ()
    10741155{
    1075     QSpinBox * s;
    1076     QCheckBox * c;
    1077     QComboBox * m;
    1078     QHBoxLayout * h;
    1079     QDoubleSpinBox * ds;
    1080     const QString speed_K_str = Formatter::unitStr (Formatter::SPEED, Formatter::KB);
    1081 
    1082     HIG * hig = new HIG (this);
    1083     hig->addSectionTitle (tr ("Speed"));
    1084 
    1085     c = new QCheckBox (tr ("Honor global &limits"));
    1086     mySessionLimitCheck = c;
    1087     hig->addWideControl (c);
    1088     connect (c, SIGNAL (clicked (bool)), this, SLOT (onHonorsSessionLimitsToggled (bool)));
    1089 
    1090     c = new QCheckBox (tr ("Limit &download speed (%1):").arg (speed_K_str));
    1091     mySingleDownCheck = c;
    1092     s = new QSpinBox ();
    1093     s->setProperty (PREF_KEY, TR_KEY_downloadLimit);
    1094     s->setSingleStep (5);
    1095     s->setRange (0, INT_MAX);
    1096     mySingleDownSpin = s;
    1097     hig->addRow (c, s);
    1098     enableWhenChecked (c, s);
    1099     connect (c, SIGNAL (clicked (bool)), this, SLOT (onDownloadLimitedToggled (bool)));
    1100     connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
    1101 
    1102     c = new QCheckBox (tr ("Limit &upload speed (%1):").arg (speed_K_str));
    1103     mySingleUpCheck = c;
    1104     s = new QSpinBox ();
    1105     s->setSingleStep (5);
    1106     s->setRange (0, INT_MAX);
    1107     s->setProperty (PREF_KEY, TR_KEY_uploadLimit);
    1108     mySingleUpSpin = s;
    1109     hig->addRow (c, s);
    1110     enableWhenChecked (c, s);
    1111     connect (c, SIGNAL (clicked (bool)), this, SLOT (onUploadLimitedToggled (bool)));
    1112     connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
    1113 
    1114     m = new QComboBox;
    1115     m->addItem (tr ("High"),   TR_PRI_HIGH);
    1116     m->addItem (tr ("Normal"), TR_PRI_NORMAL);
    1117     m->addItem (tr ("Low"),    TR_PRI_LOW);
    1118     connect (m, SIGNAL (currentIndexChanged (int)), this, SLOT (onBandwidthPriorityChanged (int)));
    1119     hig->addRow (tr ("Torrent &priority:"), m);
    1120     myBandwidthPriorityCombo = m;
    1121 
    1122     hig->addSectionDivider ();
    1123     hig->addSectionTitle (tr ("Seeding Limits"));
    1124 
    1125     h = new QHBoxLayout ();
    1126     h->setSpacing (HIG :: PAD);
    1127     m = new QComboBox;
    1128     m->addItem (tr ("Use Global Settings"),      TR_RATIOLIMIT_GLOBAL);
    1129     m->addItem (tr ("Seed regardless of ratio"), TR_RATIOLIMIT_UNLIMITED);
    1130     m->addItem (tr ("Stop seeding at ratio:"),   TR_RATIOLIMIT_SINGLE);
    1131     connect (m, SIGNAL (currentIndexChanged (int)), this, SLOT (onRatioModeChanged (int)));
    1132     h->addWidget (myRatioCombo = m);
    1133     ds = new QDoubleSpinBox ();
    1134     ds->setRange (0.5, INT_MAX);
    1135     ds->setProperty (PREF_KEY, TR_KEY_seedRatioLimit);
    1136     connect (ds, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
    1137     h->addWidget (myRatioSpin = ds);
    1138     hig->addRow (tr ("&Ratio:"), h, m);
    1139 
    1140     h = new QHBoxLayout ();
    1141     h->setSpacing (HIG :: PAD);
    1142     m = new QComboBox;
    1143     m->addItem (tr ("Use Global Settings"),                 TR_IDLELIMIT_GLOBAL);
    1144     m->addItem (tr ("Seed regardless of activity"),         TR_IDLELIMIT_UNLIMITED);
    1145     m->addItem (tr ("Stop seeding if idle for N minutes:"), TR_IDLELIMIT_SINGLE);
    1146     connect (m, SIGNAL (currentIndexChanged (int)), this, SLOT (onIdleModeChanged (int)));
    1147     h->addWidget (myIdleCombo = m);
    1148     s = new QSpinBox ();
    1149     s->setSingleStep (5);
    1150     s->setRange (1, 9999);
    1151     s->setProperty (PREF_KEY, TR_KEY_seedIdleLimit);
    1152     connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
    1153     h->addWidget (myIdleSpin = s);
    1154     hig->addRow (tr ("&Idle:"), h, m);
    1155 
    1156 
    1157     hig->addSectionDivider ();
    1158     hig->addSectionTitle (tr ("Peer Connections"));
    1159 
    1160     s = new QSpinBox ();
    1161     s->setSingleStep (5);
    1162     s->setRange (1, 300);
    1163     s->setProperty (PREF_KEY, TR_KEY_peer_limit);
    1164     connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
    1165     myPeerLimitSpin = s;
    1166     hig->addRow (tr ("&Maximum peers:"), s);
    1167 
    1168     hig->finish ();
    1169 
    1170     return hig;
     1156  QSpinBox * s;
     1157  QCheckBox * c;
     1158  QComboBox * m;
     1159  QHBoxLayout * h;
     1160  QDoubleSpinBox * ds;
     1161  const QString speed_K_str = Formatter::unitStr (Formatter::SPEED, Formatter::KB);
     1162
     1163  HIG * hig = new HIG (this);
     1164  hig->addSectionTitle (tr ("Speed"));
     1165
     1166  c = new QCheckBox (tr ("Honor global &limits"));
     1167  mySessionLimitCheck = c;
     1168  hig->addWideControl (c);
     1169  connect (c, SIGNAL (clicked (bool)), this, SLOT (onHonorsSessionLimitsToggled (bool)));
     1170
     1171  c = new QCheckBox (tr ("Limit &download speed (%1):").arg (speed_K_str));
     1172  mySingleDownCheck = c;
     1173  s = new QSpinBox ();
     1174  s->setProperty (PREF_KEY, TR_KEY_downloadLimit);
     1175  s->setSingleStep (5);
     1176  s->setRange (0, INT_MAX);
     1177  mySingleDownSpin = s;
     1178  hig->addRow (c, s);
     1179  enableWhenChecked (c, s);
     1180  connect (c, SIGNAL (clicked (bool)), this, SLOT (onDownloadLimitedToggled (bool)));
     1181  connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
     1182
     1183  c = new QCheckBox (tr ("Limit &upload speed (%1):").arg (speed_K_str));
     1184  mySingleUpCheck = c;
     1185  s = new QSpinBox ();
     1186  s->setSingleStep (5);
     1187  s->setRange (0, INT_MAX);
     1188  s->setProperty (PREF_KEY, TR_KEY_uploadLimit);
     1189  mySingleUpSpin = s;
     1190  hig->addRow (c, s);
     1191  enableWhenChecked (c, s);
     1192  connect (c, SIGNAL (clicked (bool)), this, SLOT (onUploadLimitedToggled (bool)));
     1193  connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
     1194
     1195  m = new QComboBox;
     1196  m->addItem (tr ("High"),   TR_PRI_HIGH);
     1197  m->addItem (tr ("Normal"), TR_PRI_NORMAL);
     1198  m->addItem (tr ("Low"),    TR_PRI_LOW);
     1199  connect (m, SIGNAL (currentIndexChanged (int)), this, SLOT (onBandwidthPriorityChanged (int)));
     1200  hig->addRow (tr ("Torrent &priority:"), m);
     1201  myBandwidthPriorityCombo = m;
     1202
     1203  hig->addSectionDivider ();
     1204  hig->addSectionTitle (tr ("Seeding Limits"));
     1205
     1206  h = new QHBoxLayout ();
     1207  h->setSpacing (HIG :: PAD);
     1208  m = new QComboBox;
     1209  m->addItem (tr ("Use Global Settings"),      TR_RATIOLIMIT_GLOBAL);
     1210  m->addItem (tr ("Seed regardless of ratio"), TR_RATIOLIMIT_UNLIMITED);
     1211  m->addItem (tr ("Stop seeding at ratio:"),   TR_RATIOLIMIT_SINGLE);
     1212  connect (m, SIGNAL (currentIndexChanged (int)), this, SLOT (onRatioModeChanged (int)));
     1213  h->addWidget (myRatioCombo = m);
     1214  ds = new QDoubleSpinBox ();
     1215  ds->setRange (0.5, INT_MAX);
     1216  ds->setProperty (PREF_KEY, TR_KEY_seedRatioLimit);
     1217  connect (ds, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
     1218  h->addWidget (myRatioSpin = ds);
     1219  hig->addRow (tr ("&Ratio:"), h, m);
     1220
     1221  h = new QHBoxLayout ();
     1222  h->setSpacing (HIG :: PAD);
     1223  m = new QComboBox;
     1224  m->addItem (tr ("Use Global Settings"),                 TR_IDLELIMIT_GLOBAL);
     1225  m->addItem (tr ("Seed regardless of activity"),         TR_IDLELIMIT_UNLIMITED);
     1226  m->addItem (tr ("Stop seeding if idle for N minutes:"), TR_IDLELIMIT_SINGLE);
     1227  connect (m, SIGNAL (currentIndexChanged (int)), this, SLOT (onIdleModeChanged (int)));
     1228  h->addWidget (myIdleCombo = m);
     1229  s = new QSpinBox ();
     1230  s->setSingleStep (5);
     1231  s->setRange (1, 9999);
     1232  s->setProperty (PREF_KEY, TR_KEY_seedIdleLimit);
     1233  connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
     1234  h->addWidget (myIdleSpin = s);
     1235  hig->addRow (tr ("&Idle:"), h, m);
     1236
     1237
     1238  hig->addSectionDivider ();
     1239  hig->addSectionTitle (tr ("Peer Connections"));
     1240
     1241  s = new QSpinBox ();
     1242  s->setSingleStep (5);
     1243  s->setRange (1, 300);
     1244  s->setProperty (PREF_KEY, TR_KEY_peer_limit);
     1245  connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ()));
     1246  myPeerLimitSpin = s;
     1247  hig->addRow (tr ("&Maximum peers:"), s);
     1248
     1249  hig->finish ();
     1250
     1251  return hig;
    11711252}
    11721253
     
    11781259Details :: createTrackerTab ()
    11791260{
    1180     QCheckBox * c;
    1181     QPushButton * p;
    1182     QWidget * top = new QWidget;
    1183     QVBoxLayout * v = new QVBoxLayout (top);
    1184     QHBoxLayout * h = new QHBoxLayout ();
    1185     QVBoxLayout * v2 = new QVBoxLayout ();
    1186 
    1187     v->setSpacing (HIG::PAD_BIG);
    1188     v->setContentsMargins (HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG);
    1189 
    1190     h->setSpacing (HIG::PAD);
    1191     h->setContentsMargins (HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL);
    1192 
    1193     v2->setSpacing (HIG::PAD);
    1194 
    1195     myTrackerModel = new TrackerModel;
    1196     myTrackerFilter = new TrackerModelFilter;
    1197     myTrackerFilter->setSourceModel (myTrackerModel);
    1198     myTrackerView = new QTreeView;
    1199     myTrackerView->setModel (myTrackerFilter);
    1200     myTrackerView->setHeaderHidden (true);
    1201     myTrackerView->setSelectionMode (QTreeWidget::ExtendedSelection);
    1202     myTrackerView->setRootIsDecorated (false);
    1203     myTrackerView->setIndentation (2);
    1204     myTrackerView->setItemsExpandable (false);
    1205     myTrackerView->setAlternatingRowColors (true);
    1206     myTrackerView->setItemDelegate (myTrackerDelegate = new TrackerDelegate ());
    1207     connect (myTrackerView->selectionModel (), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT (onTrackerSelectionChanged ()));
    1208     h->addWidget (myTrackerView, 1);
    1209 
    1210     p = new QPushButton ();
    1211     p->setIcon (getStockIcon ("list-add", QStyle::SP_DialogOpenButton));
    1212     p->setToolTip (tr ("Add Tracker"));
    1213     myAddTrackerButton = p;
    1214     v2->addWidget (p, 1);
    1215     connect (p, SIGNAL (clicked (bool)), this, SLOT (onAddTrackerClicked ()));
    1216 
    1217     p = new QPushButton ();
    1218     p->setIcon (getStockIcon ("document-properties", QStyle::SP_DesktopIcon));
    1219     p->setToolTip (tr ("Edit Tracker"));
    1220     myAddTrackerButton = p;
    1221     p->setEnabled (false);
    1222     myEditTrackerButton = p;
    1223     v2->addWidget (p, 1);
    1224     connect (p, SIGNAL (clicked (bool)), this, SLOT (onEditTrackerClicked ()));
    1225 
    1226     p = new QPushButton ();
    1227     p->setIcon (getStockIcon ("list-remove", QStyle::SP_TrashIcon));
    1228     p->setToolTip (tr ("Remove Trackers"));
    1229     p->setEnabled (false);
    1230     myRemoveTrackerButton = p;
    1231     v2->addWidget (p, 1);
    1232     connect (p, SIGNAL (clicked (bool)), this, SLOT (onRemoveTrackerClicked ()));
    1233 
    1234     v2->addStretch (1);
    1235 
    1236     h->addLayout (v2, 1);
    1237     h->setStretch (1, 0);
    1238 
    1239     v->addLayout (h, 1);
    1240 
    1241     c = new QCheckBox (tr ("Show &more details"));
    1242     c->setChecked (myPrefs.getBool (Prefs::SHOW_TRACKER_SCRAPES));
    1243     myShowTrackerScrapesCheck = c;
    1244     v->addWidget (c, 1);
    1245     connect (c, SIGNAL (clicked (bool)), this, SLOT (onShowTrackerScrapesToggled (bool)));
    1246 
    1247     c = new QCheckBox (tr ("Show &backup trackers"));
    1248     c->setChecked (myPrefs.getBool (Prefs::SHOW_BACKUP_TRACKERS));
    1249     myShowBackupTrackersCheck = c;
    1250     v->addWidget (c, 1);
    1251     connect (c, SIGNAL (clicked (bool)), this, SLOT (onShowBackupTrackersToggled (bool)));
    1252 
    1253     return top;
     1261  QCheckBox * c;
     1262  QPushButton * p;
     1263  QWidget * top = new QWidget;
     1264  QVBoxLayout * v = new QVBoxLayout (top);
     1265  QHBoxLayout * h = new QHBoxLayout ();
     1266  QVBoxLayout * v2 = new QVBoxLayout ();
     1267
     1268  v->setSpacing (HIG::PAD_BIG);
     1269  v->setContentsMargins (HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG);
     1270
     1271  h->setSpacing (HIG::PAD);
     1272  h->setContentsMargins (HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL);
     1273
     1274  v2->setSpacing (HIG::PAD);
     1275
     1276  myTrackerModel = new TrackerModel;
     1277  myTrackerFilter = new TrackerModelFilter;
     1278  myTrackerFilter->setSourceModel (myTrackerModel);
     1279  myTrackerView = new QTreeView;
     1280  myTrackerView->setModel (myTrackerFilter);
     1281  myTrackerView->setHeaderHidden (true);
     1282  myTrackerView->setSelectionMode (QTreeWidget::ExtendedSelection);
     1283  myTrackerView->setRootIsDecorated (false);
     1284  myTrackerView->setIndentation (2);
     1285  myTrackerView->setItemsExpandable (false);
     1286  myTrackerView->setAlternatingRowColors (true);
     1287  myTrackerView->setItemDelegate (myTrackerDelegate = new TrackerDelegate ());
     1288  connect (myTrackerView->selectionModel (), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT (onTrackerSelectionChanged ()));
     1289  h->addWidget (myTrackerView, 1);
     1290
     1291  p = new QPushButton ();
     1292  p->setIcon (getStockIcon ("list-add", QStyle::SP_DialogOpenButton));
     1293  p->setToolTip (tr ("Add Tracker"));
     1294  myAddTrackerButton = p;
     1295  v2->addWidget (p, 1);
     1296  connect (p, SIGNAL (clicked (bool)), this, SLOT (onAddTrackerClicked ()));
     1297
     1298  p = new QPushButton ();
     1299  p->setIcon (getStockIcon ("document-properties", QStyle::SP_DesktopIcon));
     1300  p->setToolTip (tr ("Edit Tracker"));
     1301  myAddTrackerButton = p;
     1302  p->setEnabled (false);
     1303  myEditTrackerButton = p;
     1304  v2->addWidget (p, 1);
     1305  connect (p, SIGNAL (clicked (bool)), this, SLOT (onEditTrackerClicked ()));
     1306
     1307  p = new QPushButton ();
     1308  p->setIcon (getStockIcon ("list-remove", QStyle::SP_TrashIcon));
     1309  p->setToolTip (tr ("Remove Trackers"));
     1310  p->setEnabled (false);
     1311  myRemoveTrackerButton = p;
     1312  v2->addWidget (p, 1);
     1313  connect (p, SIGNAL (clicked (bool)), this, SLOT (onRemoveTrackerClicked ()));
     1314
     1315  v2->addStretch (1);
     1316
     1317  h->addLayout (v2, 1);
     1318  h->setStretch (1, 0);
     1319
     1320  v->addLayout (h, 1);
     1321
     1322  c = new QCheckBox (tr ("Show &more details"));
     1323  c->setChecked (myPrefs.getBool (Prefs::SHOW_TRACKER_SCRAPES));
     1324  myShowTrackerScrapesCheck = c;
     1325  v->addWidget (c, 1);
     1326  connect (c, SIGNAL (clicked (bool)), this, SLOT (onShowTrackerScrapesToggled (bool)));
     1327
     1328  c = new QCheckBox (tr ("Show &backup trackers"));
     1329  c->setChecked (myPrefs.getBool (Prefs::SHOW_BACKUP_TRACKERS));
     1330  myShowBackupTrackersCheck = c;
     1331  v->addWidget (c, 1);
     1332  connect (c, SIGNAL (clicked (bool)), this, SLOT (onShowBackupTrackersToggled (bool)));
     1333
     1334  return top;
    12541335}
    12551336
     
    12611342Details :: createPeersTab ()
    12621343{
    1263     QWidget * top = new QWidget;
    1264     QVBoxLayout * v = new QVBoxLayout (top);
    1265     v->setSpacing (HIG :: PAD_BIG);
    1266     v->setContentsMargins (HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG);
    1267 
    1268     QStringList headers;
    1269     headers << QString () << tr ("Up") << tr ("Down") << tr ("%") << tr ("Status") << tr ("Address") << tr ("Client");
    1270     myPeerTree = new QTreeWidget;
    1271     myPeerTree->setUniformRowHeights (true);
    1272     myPeerTree->setHeaderLabels (headers);
    1273     myPeerTree->setColumnWidth (0, 20);
    1274     myPeerTree->setSortingEnabled (true);
    1275     myPeerTree->sortByColumn (COL_ADDRESS, Qt::AscendingOrder);
    1276     myPeerTree->setRootIsDecorated (false);
    1277     myPeerTree->setTextElideMode (Qt::ElideRight);
    1278     v->addWidget (myPeerTree, 1);
    1279 
    1280     const QFontMetrics m (font ());
    1281     QSize size = m.size (0, "1024 MiB/s");
    1282     myPeerTree->setColumnWidth (COL_UP, size.width ());
    1283     myPeerTree->setColumnWidth (COL_DOWN, size.width ());
    1284     size = m.size (0, " 100% ");
    1285     myPeerTree->setColumnWidth (COL_PERCENT, size.width ());
    1286     size = m.size (0, "ODUK?EXI");
    1287     myPeerTree->setColumnWidth (COL_STATUS, size.width ());
    1288     size = m.size (0, "888.888.888.888");
    1289     myPeerTree->setColumnWidth (COL_ADDRESS, size.width ());
    1290     size = m.size (0, "Some BitTorrent Client");
    1291     myPeerTree->setColumnWidth (COL_CLIENT, size.width ());
    1292     myPeerTree->setAlternatingRowColors (true);
    1293 
    1294     return top;
     1344  QWidget * top = new QWidget;
     1345  QVBoxLayout * v = new QVBoxLayout (top);
     1346  v->setSpacing (HIG :: PAD_BIG);
     1347  v->setContentsMargins (HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG);
     1348
     1349  QStringList headers;
     1350  headers << QString () << tr ("Up") << tr ("Down") << tr ("%") << tr ("Status") << tr ("Address") << tr ("Client");
     1351  myPeerTree = new QTreeWidget;
     1352  myPeerTree->setUniformRowHeights (true);
     1353  myPeerTree->setHeaderLabels (headers);
     1354  myPeerTree->setColumnWidth (0, 20);
     1355  myPeerTree->setSortingEnabled (true);
     1356  myPeerTree->sortByColumn (COL_ADDRESS, Qt::AscendingOrder);
     1357  myPeerTree->setRootIsDecorated (false);
     1358  myPeerTree->setTextElideMode (Qt::ElideRight);
     1359  v->addWidget (myPeerTree, 1);
     1360
     1361  const QFontMetrics m (font ());
     1362  QSize size = m.size (0, "1024 MiB/s");
     1363  myPeerTree->setColumnWidth (COL_UP, size.width ());
     1364  myPeerTree->setColumnWidth (COL_DOWN, size.width ());
     1365  size = m.size (0, " 100% ");
     1366  myPeerTree->setColumnWidth (COL_PERCENT, size.width ());
     1367  size = m.size (0, "ODUK?EXI");
     1368  myPeerTree->setColumnWidth (COL_STATUS, size.width ());
     1369  size = m.size (0, "888.888.888.888");
     1370  myPeerTree->setColumnWidth (COL_ADDRESS, size.width ());
     1371  size = m.size (0, "Some BitTorrent Client");
     1372  myPeerTree->setColumnWidth (COL_CLIENT, size.width ());
     1373  myPeerTree->setAlternatingRowColors (true);
     1374
     1375  return top;
    12951376}
    12961377
     
    13021383Details :: createFilesTab ()
    13031384{
    1304     myFileTreeView = new FileTreeView ();
    1305 
    1306     connect (myFileTreeView, SIGNAL (     priorityChanged (const QSet<int>&, int)),
    1307              this,           SLOT ( onFilePriorityChanged (const QSet<int>&, int)));
    1308 
    1309     connect (myFileTreeView, SIGNAL (     wantedChanged (const QSet<int>&, bool)),
    1310              this,           SLOT ( onFileWantedChanged (const QSet<int>&, bool)));
    1311 
    1312     connect (myFileTreeView, SIGNAL (pathEdited (const QString&, const QString&)),
    1313              this,           SLOT (onPathEdited (const QString&, const QString&)));
    1314 
    1315     return myFileTreeView;
     1385  myFileTreeView = new FileTreeView ();
     1386
     1387  connect (myFileTreeView, SIGNAL (     priorityChanged (const QSet<int>&, int)),
     1388           this,           SLOT ( onFilePriorityChanged (const QSet<int>&, int)));
     1389
     1390  connect (myFileTreeView, SIGNAL (     wantedChanged (const QSet<int>&, bool)),
     1391           this,           SLOT ( onFileWantedChanged (const QSet<int>&, bool)));
     1392
     1393  connect (myFileTreeView, SIGNAL (pathEdited (const QString&, const QString&)),
     1394           this,           SLOT (onPathEdited (const QString&, const QString&)));
     1395
     1396  return myFileTreeView;
    13161397}
    13171398
     
    13371418
    13381419  mySession.torrentSet (myIds, key, indices.toList ());
    1339     getNewData ();
     1420  getNewData ();
    13401421}
    13411422
Note: See TracChangeset for help on using the changeset viewer.