Changeset 13869
Legend:
- Unmodified
- Added
- Removed
-
trunk/qt/about.cc
r12697 r13869 29 29 #include "license.h" 30 30 31 AboutDialog :: AboutDialog ( QWidget * parent):32 QDialog( parent, Qt::Dialog),33 myLicenseDialog( new LicenseDialog( this ))31 AboutDialog :: AboutDialog (QWidget * parent): 32 QDialog (parent, Qt::Dialog), 33 myLicenseDialog (new LicenseDialog (this)) 34 34 { 35 setWindowTitle( tr( "About Transmission" ));36 37 QVBoxLayout * v = new QVBoxLayout( this);35 setWindowTitle (tr ("About Transmission")); 36 QLabel * l; 37 QVBoxLayout * v = new QVBoxLayout (this); 38 38 39 40 l->setPixmap( QPixmap( QString::fromAscii( ":/icons/transmission-48.png" ) ));41 l->setAlignment( Qt::AlignCenter);42 v->addWidget( l);39 l = new QLabel; 40 l->setPixmap (QPixmap (QString::fromAscii (":/icons/transmission-48.png"))); 41 l->setAlignment (Qt::AlignCenter); 42 v->addWidget (l); 43 43 44 QFont f( font( ));45 f.setWeight( QFont::Bold);46 f.setPointSize( int( f.pointSize( ) * 1.2 ));47 l = new QLabel( tr( "<big>Transmission %1</big>" ).arg( QString::fromAscii( LONG_VERSION_STRING ) ));48 l->setAlignment( Qt::AlignCenter);49 l->setFont( f);50 l->setMargin( 8);51 v->addWidget( l);44 QFont f (font ()); 45 f.setWeight (QFont::Bold); 46 f.setPointSize (int (f.pointSize () * 1.2)); 47 l = new QLabel (tr ("<big>Transmission %1</big>").arg (QString::fromAscii (LONG_VERSION_STRING))); 48 l->setAlignment (Qt::AlignCenter); 49 l->setFont (f); 50 l->setMargin (8); 51 v->addWidget (l); 52 52 53 l = new QLabel( tr( "A fast and easy BitTorrent client" ));54 l->setStyleSheet( QString::fromAscii( "text-align: center" ));55 l->setAlignment( Qt::AlignCenter);56 v->addWidget( l);53 l = new QLabel (tr ("A fast and easy BitTorrent client")); 54 l->setStyleSheet (QString::fromAscii ("text-align: center")); 55 l->setAlignment (Qt::AlignCenter); 56 v->addWidget (l); 57 57 58 l = new QLabel( tr( "Copyright (c) The Transmission Project" ));59 l->setAlignment( Qt::AlignCenter);60 v->addWidget( l);58 l = new QLabel (tr ("Copyright (c) The Transmission Project")); 59 l->setAlignment (Qt::AlignCenter); 60 v->addWidget (l); 61 61 62 l = new QLabel( QString::fromAscii( "<a href=\"http://www.transmissionbt.com/\">http://www.transmissionbt.com/</a>" ));63 l->setOpenExternalLinks( true);64 l->setAlignment( Qt::AlignCenter);65 v->addWidget( l);62 l = new QLabel (QString::fromAscii ("<a href=\"http://www.transmissionbt.com/\">http://www.transmissionbt.com/</a>")); 63 l->setOpenExternalLinks (true); 64 l->setAlignment (Qt::AlignCenter); 65 v->addWidget (l); 66 66 67 v->addSpacing( HIG::PAD_BIG);67 v->addSpacing (HIG::PAD_BIG); 68 68 69 70 69 QPushButton * b; 70 QDialogButtonBox * box = new QDialogButtonBox; 71 71 72 b = new QPushButton( tr( "C&redits" ), this);73 box->addButton( b, QDialogButtonBox::ActionRole);74 connect( b, SIGNAL(clicked()), this, SLOT(showCredits()));72 b = new QPushButton (tr ("C&redits"), this); 73 box->addButton (b, QDialogButtonBox::ActionRole); 74 connect (b, SIGNAL (clicked ()), this, SLOT (showCredits ())); 75 75 76 b = new QPushButton( tr( "&License" ), this);77 box->addButton( b, QDialogButtonBox::ActionRole);78 connect( b, SIGNAL(clicked()), myLicenseDialog, SLOT(show()));76 b = new QPushButton (tr ("&License"), this); 77 box->addButton (b, QDialogButtonBox::ActionRole); 78 connect (b, SIGNAL (clicked ()), myLicenseDialog, SLOT (show ())); 79 79 80 box->addButton( QDialogButtonBox::Close);81 box->setCenterButtons( true);82 v->addWidget( box);83 connect( box, SIGNAL(rejected()), this, SLOT(hide()));80 box->addButton (QDialogButtonBox::Close); 81 box->setCenterButtons (true); 82 v->addWidget (box); 83 connect (box, SIGNAL (rejected ()), this, SLOT (hide ())); 84 84 } 85 85 86 86 void 87 AboutDialog :: showCredits ()87 AboutDialog :: showCredits () 88 88 { 89 QMessageBox::about( this, tr( "Credits" ), 90 QString::fromAscii( "Jordan Lee (Backend; Daemon; GTK+; Qt)\n" 91 "Michell Livingston (Backend; OS X)\n" 92 "Kevin Glowacz (Web client)" ) ); 89 QMessageBox::about ( 90 this, 91 tr ("Credits"), 92 QString::fromAscii ("Jordan Lee (Backend; Daemon; GTK+; Qt)\n" 93 "Michell Livingston (OS X)\n")); 93 94 } 94 95 -
trunk/qt/about.h
r11092 r13869 18 18 class AboutDialog: public QDialog 19 19 { 20 20 Q_OBJECT 21 21 22 23 22 private: 23 QDialog * myLicenseDialog; 24 24 25 26 AboutDialog( QWidget * parent = 0);27 ~AboutDialog( ) {}28 QWidget * createAboutTab();29 QWidget * createAuthorsTab();30 QWidget * createLicenseTab();25 public: 26 AboutDialog (QWidget * parent = 0); 27 ~AboutDialog () {} 28 QWidget * createAboutTab (); 29 QWidget * createAuthorsTab (); 30 QWidget * createLicenseTab (); 31 31 32 33 void showCredits();32 public slots: 33 void showCredits (); 34 34 35 35 }; -
trunk/qt/app.cc
r13841 r13869 46 46 namespace 47 47 { 48 const QString DBUS_SERVICE = QString::fromAscii( "com.transmissionbt.Transmission" ); 49 const QString DBUS_OBJECT_PATH = QString::fromAscii( "/com/transmissionbt/Transmission" ); 50 const QString DBUS_INTERFACE = QString::fromAscii( "com.transmissionbt.Transmission" ); 51 52 const char * MY_READABLE_NAME( "transmission-qt" ); 53 54 const tr_option opts[] = 55 { 56 { 'g', "config-dir", "Where to look for configuration files", "g", 1, "<path>" }, 57 { 'm', "minimized", "Start minimized in system tray", "m", 0, NULL }, 58 { 'p', "port", "Port to use when connecting to an existing session", "p", 1, "<port>" }, 59 { 'r', "remote", "Connect to an existing session at the specified hostname", "r", 1, "<host>" }, 60 { 'u', "username", "Username to use when connecting to an existing session", "u", 1, "<username>" }, 61 { 'v', "version", "Show version number and exit", "v", 0, NULL }, 62 { 'w', "password", "Password to use when connecting to an existing session", "w", 1, "<password>" }, 63 { 0, NULL, NULL, NULL, 0, NULL } 64 }; 65 66 const char* 67 getUsage( void ) 68 { 69 return "Usage:\n" 70 " transmission [OPTIONS...] [torrent files]"; 71 } 72 73 void 74 showUsage( void ) 75 { 76 tr_getopt_usage( MY_READABLE_NAME, getUsage( ), opts ); 77 exit( 0 ); 78 } 79 80 enum 81 { 82 STATS_REFRESH_INTERVAL_MSEC = 3000, 83 SESSION_REFRESH_INTERVAL_MSEC = 3000, 84 MODEL_REFRESH_INTERVAL_MSEC = 3000 85 }; 86 } 87 88 MyApp :: MyApp( int& argc, char ** argv ): 89 QApplication( argc, argv ), 90 myLastFullUpdateTime( 0 ) 91 { 92 const QString MY_CONFIG_NAME = QString::fromAscii( "transmission" ); 93 94 setApplicationName( MY_CONFIG_NAME ); 95 96 // install the qt translator 97 qtTranslator.load( "qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); 98 installTranslator( &qtTranslator ); 99 100 // install the transmission translator 101 appTranslator.load( QString(MY_CONFIG_NAME) + "_" + QLocale::system().name(), QCoreApplication::applicationDirPath() + "/translations" ); 102 installTranslator( &appTranslator ); 103 104 Formatter::initUnits( ); 105 106 // set the default icon 107 QIcon icon; 108 QList<int> sizes; 109 sizes << 16 << 22 << 24 << 32 << 48 << 64 << 72 << 96 << 128 << 192 << 256; 110 foreach( int size, sizes ) 111 icon.addPixmap( QPixmap( QString::fromAscii(":/icons/transmission-%1.png" ).arg(size) ) ); 112 setWindowIcon( icon ); 113 114 // parse the command-line arguments 115 int c; 116 bool minimized = false; 117 const char * optarg; 118 const char * host = 0; 119 const char * port = 0; 120 const char * username = 0; 121 const char * password = 0; 122 const char * configDir = 0; 123 QStringList filenames; 124 while( ( c = tr_getopt( getUsage( ), argc, (const char**)argv, opts, &optarg ) ) ) { 125 switch( c ) { 126 case 'g': configDir = optarg; break; 127 case 'p': port = optarg; break; 128 case 'r': host = optarg; break; 129 case 'u': username = optarg; break; 130 case 'w': password = optarg; break; 131 case 'm': minimized = true; break; 132 case 'v': std::cerr << MY_READABLE_NAME << ' ' << LONG_VERSION_STRING << std::endl; ::exit( 0 ); break; 133 case TR_OPT_ERR: Utils::toStderr( QObject::tr( "Invalid option" ) ); showUsage( ); break; 134 default: filenames.append( optarg ); break; 48 const QString DBUS_SERVICE = QString::fromAscii ("com.transmissionbt.Transmission" ); 49 const QString DBUS_OBJECT_PATH = QString::fromAscii ("/com/transmissionbt/Transmission"); 50 const QString DBUS_INTERFACE = QString::fromAscii ("com.transmissionbt.Transmission" ); 51 52 const char * MY_READABLE_NAME ("transmission-qt"); 53 54 const tr_option opts[] = 55 { 56 { 'g', "config-dir", "Where to look for configuration files", "g", 1, "<path>" }, 57 { 'm', "minimized", "Start minimized in system tray", "m", 0, NULL }, 58 { 'p', "port", "Port to use when connecting to an existing session", "p", 1, "<port>" }, 59 { 'r', "remote", "Connect to an existing session at the specified hostname", "r", 1, "<host>" }, 60 { 'u', "username", "Username to use when connecting to an existing session", "u", 1, "<username>" }, 61 { 'v', "version", "Show version number and exit", "v", 0, NULL }, 62 { 'w', "password", "Password to use when connecting to an existing session", "w", 1, "<password>" }, 63 { 0, NULL, NULL, NULL, 0, NULL } 64 }; 65 66 const char* 67 getUsage (void) 68 { 69 return "Usage:\n" 70 " transmission [OPTIONS...] [torrent files]"; 71 } 72 73 void 74 showUsage (void) 75 { 76 tr_getopt_usage (MY_READABLE_NAME, getUsage (), opts); 77 exit (0); 78 } 79 80 enum 81 { 82 STATS_REFRESH_INTERVAL_MSEC = 3000, 83 SESSION_REFRESH_INTERVAL_MSEC = 3000, 84 MODEL_REFRESH_INTERVAL_MSEC = 3000 85 }; 86 } 87 88 MyApp :: MyApp (int& argc, char ** argv): 89 QApplication (argc, argv), 90 myLastFullUpdateTime (0) 91 { 92 const QString MY_CONFIG_NAME = QString::fromAscii ("transmission"); 93 94 setApplicationName (MY_CONFIG_NAME); 95 96 // install the qt translator 97 qtTranslator.load ("qt_" + QLocale::system ().name (), QLibraryInfo::location (QLibraryInfo::TranslationsPath)); 98 installTranslator (&qtTranslator); 99 100 // install the transmission translator 101 appTranslator.load (QString (MY_CONFIG_NAME) + "_" + QLocale::system ().name (), QCoreApplication::applicationDirPath () + "/translations"); 102 installTranslator (&appTranslator); 103 104 Formatter::initUnits (); 105 106 // set the default icon 107 QIcon icon; 108 QList<int> sizes; 109 sizes << 16 << 22 << 24 << 32 << 48 << 64 << 72 << 96 << 128 << 192 << 256; 110 foreach (int size, sizes) 111 icon.addPixmap (QPixmap (QString::fromAscii (":/icons/transmission-%1.png").arg (size))); 112 setWindowIcon (icon); 113 114 // parse the command-line arguments 115 int c; 116 bool minimized = false; 117 const char * optarg; 118 const char * host = 0; 119 const char * port = 0; 120 const char * username = 0; 121 const char * password = 0; 122 const char * configDir = 0; 123 QStringList filenames; 124 while ((c = tr_getopt (getUsage(), argc, (const char**)argv, opts, &optarg))) 125 { 126 switch (c) 127 { 128 case 'g': configDir = optarg; break; 129 case 'p': port = optarg; break; 130 case 'r': host = optarg; break; 131 case 'u': username = optarg; break; 132 case 'w': password = optarg; break; 133 case 'm': minimized = true; break; 134 case 'v': std::cerr << MY_READABLE_NAME << ' ' << LONG_VERSION_STRING << std::endl; ::exit (0); break; 135 case TR_OPT_ERR: Utils::toStderr (QObject::tr ("Invalid option")); showUsage (); break; 136 default: filenames.append (optarg); break; 135 137 } 136 138 } 137 139 138 // set the fallback config dir 139 if( configDir == 0 ) 140 configDir = tr_getDefaultConfigDir( "transmission" ); 141 142 // ensure our config directory exists 143 QDir dir( configDir ); 144 if( !dir.exists() ) 145 dir.mkpath( configDir ); 146 147 // is this the first time we've run transmission? 148 const bool firstTime = !QFile(QDir(configDir).absoluteFilePath("settings.json")).exists(); 149 150 // initialize the prefs 151 myPrefs = new Prefs ( configDir ); 152 if( host != 0 ) 153 myPrefs->set( Prefs::SESSION_REMOTE_HOST, host ); 154 if( port != 0 ) 155 myPrefs->set( Prefs::SESSION_REMOTE_PORT, port ); 156 if( username != 0 ) 157 myPrefs->set( Prefs::SESSION_REMOTE_USERNAME, username ); 158 if( password != 0 ) 159 myPrefs->set( Prefs::SESSION_REMOTE_PASSWORD, password ); 160 if( ( host != 0 ) || ( port != 0 ) || ( username != 0 ) || ( password != 0 ) ) 161 myPrefs->set( Prefs::SESSION_IS_REMOTE, true ); 162 if ( myPrefs->getBool( Prefs::START_MINIMIZED) ) 163 minimized = true; 164 165 // start as minimized only if the system tray present 166 if ( !myPrefs->getBool( Prefs::SHOW_TRAY_ICON ) ) 167 minimized = false; 168 169 mySession = new Session( configDir, *myPrefs ); 170 myModel = new TorrentModel( *myPrefs ); 171 myWindow = new TrMainWindow( *mySession, *myPrefs, *myModel, minimized ); 172 myWatchDir = new WatchDir( *myModel ); 173 174 // when the session gets torrent info, update the model 175 connect( mySession, SIGNAL(torrentsUpdated(tr_variant*,bool)), myModel, SLOT(updateTorrents(tr_variant*,bool)) ); 176 connect( mySession, SIGNAL(torrentsUpdated(tr_variant*,bool)), myWindow, SLOT(refreshActionSensitivity()) ); 177 connect( mySession, SIGNAL(torrentsRemoved(tr_variant*)), myModel, SLOT(removeTorrents(tr_variant*)) ); 178 // when the session source gets changed, request a full refresh 179 connect( mySession, SIGNAL(sourceChanged()), this, SLOT(onSessionSourceChanged()) ); 180 // when the model sees a torrent for the first time, ask the session for full info on it 181 connect( myModel, SIGNAL(torrentsAdded(QSet<int>)), mySession, SLOT(initTorrents(QSet<int>)) ); 182 connect( myModel, SIGNAL(torrentsAdded(QSet<int>)), this, SLOT(onTorrentsAdded(QSet<int>)) ); 183 184 mySession->initTorrents( ); 185 mySession->refreshSessionStats( ); 186 187 // when torrents are added to the watch directory, tell the session 188 connect( myWatchDir, SIGNAL(torrentFileAdded(QString)), this, SLOT(addTorrent(QString)) ); 189 190 // init from preferences 191 QList<int> initKeys; 192 initKeys << Prefs::DIR_WATCH; 193 foreach( int key, initKeys ) 194 refreshPref( key ); 195 connect( myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(const int)) ); 196 197 QTimer * timer = &myModelTimer; 198 connect( timer, SIGNAL(timeout()), this, SLOT(refreshTorrents()) ); 199 timer->setSingleShot( false ); 200 timer->setInterval( MODEL_REFRESH_INTERVAL_MSEC ); 201 timer->start( ); 202 203 timer = &myStatsTimer; 204 connect( timer, SIGNAL(timeout()), mySession, SLOT(refreshSessionStats()) ); 205 timer->setSingleShot( false ); 206 timer->setInterval( STATS_REFRESH_INTERVAL_MSEC ); 207 timer->start( ); 208 209 timer = &mySessionTimer; 210 connect( timer, SIGNAL(timeout()), mySession, SLOT(refreshSessionInfo()) ); 211 timer->setSingleShot( false ); 212 timer->setInterval( SESSION_REFRESH_INTERVAL_MSEC ); 213 timer->start( ); 214 215 maybeUpdateBlocklist( ); 216 217 if( !firstTime ) 218 mySession->restart( ); 219 else { 220 QDialog * d = new SessionDialog( *mySession, *myPrefs, myWindow ); 221 d->show( ); 222 } 223 224 if( !myPrefs->getBool( Prefs::USER_HAS_GIVEN_INFORMED_CONSENT )) 225 { 226 QDialog * dialog = new QDialog( myWindow ); 227 dialog->setModal( true ); 228 QVBoxLayout * v = new QVBoxLayout( dialog ); 229 QLabel * l = new QLabel(tr("Transmission is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.")); 230 l->setWordWrap( true ); 231 v->addWidget( l ); 232 QDialogButtonBox * box = new QDialogButtonBox; 233 box->addButton( new QPushButton( tr( "&Cancel" ) ), QDialogButtonBox::RejectRole ); 234 QPushButton * agree = new QPushButton( tr( "I &Agree" ) ); 235 agree->setDefault( true ); 236 box->addButton( agree, QDialogButtonBox::AcceptRole ); 237 box->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); 238 box->setOrientation( Qt::Horizontal ); 239 v->addWidget( box ); 240 connect( box, SIGNAL(rejected()), this, SLOT(quit()) ); 241 connect( box, SIGNAL(accepted()), dialog, SLOT(deleteLater()) ); 242 connect( box, SIGNAL(accepted()), this, SLOT(consentGiven()) ); 243 dialog->show(); 244 } 245 246 for( QStringList::const_iterator it=filenames.begin(), end=filenames.end(); it!=end; ++it ) 247 addTorrent( *it ); 248 249 // register as the dbus handler for Transmission 250 new TrDBusAdaptor( this ); 251 QDBusConnection bus = QDBusConnection::sessionBus(); 252 if( !bus.registerService( DBUS_SERVICE ) ) 253 std::cerr << "couldn't register " << qPrintable(DBUS_SERVICE) << std::endl; 254 if( !bus.registerObject( DBUS_OBJECT_PATH, this ) ) 255 std::cerr << "couldn't register " << qPrintable(DBUS_OBJECT_PATH) << std::endl; 140 // set the fallback config dir 141 if (configDir == 0) 142 configDir = tr_getDefaultConfigDir ("transmission"); 143 144 // ensure our config directory exists 145 QDir dir (configDir); 146 if (!dir.exists ()) 147 dir.mkpath (configDir); 148 149 // is this the first time we've run transmission? 150 const bool firstTime = !QFile (QDir (configDir).absoluteFilePath ("settings.json")).exists (); 151 152 // initialize the prefs 153 myPrefs = new Prefs (configDir); 154 if (host != 0) 155 myPrefs->set (Prefs::SESSION_REMOTE_HOST, host); 156 if (port != 0) 157 myPrefs->set (Prefs::SESSION_REMOTE_PORT, port); 158 if (username != 0) 159 myPrefs->set (Prefs::SESSION_REMOTE_USERNAME, username); 160 if (password != 0) 161 myPrefs->set (Prefs::SESSION_REMOTE_PASSWORD, password); 162 if ((host != 0) || (port != 0) || (username != 0) || (password != 0)) 163 myPrefs->set (Prefs::SESSION_IS_REMOTE, true); 164 if (myPrefs->getBool (Prefs::START_MINIMIZED)) 165 minimized = true; 166 167 // start as minimized only if the system tray present 168 if (!myPrefs->getBool (Prefs::SHOW_TRAY_ICON)) 169 minimized = false; 170 171 mySession = new Session (configDir, *myPrefs); 172 myModel = new TorrentModel (*myPrefs); 173 myWindow = new TrMainWindow (*mySession, *myPrefs, *myModel, minimized); 174 myWatchDir = new WatchDir (*myModel); 175 176 // when the session gets torrent info, update the model 177 connect (mySession, SIGNAL (torrentsUpdated (tr_variant*,bool)), myModel, SLOT (updateTorrents (tr_variant*,bool))); 178 connect (mySession, SIGNAL (torrentsUpdated (tr_variant*,bool)), myWindow, SLOT (refreshActionSensitivity ())); 179 connect (mySession, SIGNAL (torrentsRemoved (tr_variant*)), myModel, SLOT (removeTorrents (tr_variant*))); 180 // when the session source gets changed, request a full refresh 181 connect (mySession, SIGNAL (sourceChanged ()), this, SLOT (onSessionSourceChanged ())); 182 // when the model sees a torrent for the first time, ask the session for full info on it 183 connect (myModel, SIGNAL (torrentsAdded (QSet<int>)), mySession, SLOT (initTorrents (QSet<int>))); 184 connect (myModel, SIGNAL (torrentsAdded (QSet<int>)), this, SLOT (onTorrentsAdded (QSet<int>))); 185 186 mySession->initTorrents (); 187 mySession->refreshSessionStats (); 188 189 // when torrents are added to the watch directory, tell the session 190 connect (myWatchDir, SIGNAL (torrentFileAdded (QString)), this, SLOT (addTorrent (QString))); 191 192 // init from preferences 193 QList<int> initKeys; 194 initKeys << Prefs::DIR_WATCH; 195 foreach (int key, initKeys) 196 refreshPref (key); 197 connect (myPrefs, SIGNAL (changed (int)), this, SLOT (refreshPref (const int))); 198 199 QTimer * timer = &myModelTimer; 200 connect (timer, SIGNAL (timeout ()), this, SLOT (refreshTorrents ())); 201 timer->setSingleShot (false); 202 timer->setInterval (MODEL_REFRESH_INTERVAL_MSEC); 203 timer->start (); 204 205 timer = &myStatsTimer; 206 connect (timer, SIGNAL (timeout ()), mySession, SLOT (refreshSessionStats ())); 207 timer->setSingleShot (false); 208 timer->setInterval (STATS_REFRESH_INTERVAL_MSEC); 209 timer->start (); 210 211 timer = &mySessionTimer; 212 connect (timer, SIGNAL (timeout ()), mySession, SLOT (refreshSessionInfo ())); 213 timer->setSingleShot (false); 214 timer->setInterval (SESSION_REFRESH_INTERVAL_MSEC); 215 timer->start (); 216 217 maybeUpdateBlocklist (); 218 219 if (!firstTime) 220 { 221 mySession->restart (); 222 } 223 else 224 { 225 QDialog * d = new SessionDialog (*mySession, *myPrefs, myWindow); 226 d->show (); 227 } 228 229 if (!myPrefs->getBool (Prefs::USER_HAS_GIVEN_INFORMED_CONSENT)) 230 { 231 QDialog * dialog = new QDialog (myWindow); 232 dialog->setModal (true); 233 QVBoxLayout * v = new QVBoxLayout (dialog); 234 QLabel * l = new QLabel (tr ("Transmission is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.")); 235 l->setWordWrap (true); 236 v->addWidget (l); 237 QDialogButtonBox * box = new QDialogButtonBox; 238 box->addButton (new QPushButton (tr ("&Cancel")), QDialogButtonBox::RejectRole); 239 QPushButton * agree = new QPushButton (tr ("I &Agree")); 240 agree->setDefault (true); 241 box->addButton (agree, QDialogButtonBox::AcceptRole); 242 box->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed); 243 box->setOrientation (Qt::Horizontal); 244 v->addWidget (box); 245 connect (box, SIGNAL (rejected ()), this, SLOT (quit ())); 246 connect (box, SIGNAL (accepted ()), dialog, SLOT (deleteLater ())); 247 connect (box, SIGNAL (accepted ()), this, SLOT (consentGiven ())); 248 dialog->show (); 249 } 250 251 for (QStringList::const_iterator it=filenames.begin (), end=filenames.end (); it!=end; ++it) 252 addTorrent (*it); 253 254 // register as the dbus handler for Transmission 255 new TrDBusAdaptor (this); 256 QDBusConnection bus = QDBusConnection::sessionBus (); 257 if (!bus.registerService (DBUS_SERVICE)) 258 std::cerr << "couldn't register " << qPrintable (DBUS_SERVICE) << std::endl; 259 if (!bus.registerObject (DBUS_OBJECT_PATH, this)) 260 std::cerr << "couldn't register " << qPrintable (DBUS_OBJECT_PATH) << std::endl; 256 261 } 257 262 … … 259 264 260 265 void 261 MyApp :: onTorrentsAdded( QSet<int> torrents ) 262 { 263 if( !myPrefs->getBool( Prefs::SHOW_NOTIFICATION_ON_ADD ) ) 264 return; 265 266 foreach( int id, torrents ) 267 { 268 Torrent * tor = myModel->getTorrentFromId( id ); 269 270 if( tor->name().isEmpty( ) ) // wait until the torrent's INFO fields are loaded 271 connect( tor, SIGNAL(torrentChanged(int)), this, SLOT(onNewTorrentChanged(int)) ); 272 else { 273 onNewTorrentChanged( id ); 274 if( !tor->isSeed( ) ) 275 connect( tor, SIGNAL(torrentCompleted(int)), this, SLOT(onTorrentCompleted(int)) ); 266 MyApp :: onTorrentsAdded (QSet<int> torrents) 267 { 268 if (!myPrefs->getBool (Prefs::SHOW_NOTIFICATION_ON_ADD)) 269 return; 270 271 foreach (int id, torrents) 272 { 273 Torrent * tor = myModel->getTorrentFromId (id); 274 275 if (tor->name ().isEmpty ()) // wait until the torrent's INFO fields are loaded 276 { 277 connect (tor, SIGNAL (torrentChanged (int)), this, SLOT (onNewTorrentChanged (int))); 276 278 } 277 } 278 } 279 280 void 281 MyApp :: onTorrentCompleted( int id ) 279 else 280 { 281 onNewTorrentChanged (id); 282 283 if (!tor->isSeed ()) 284 connect (tor, SIGNAL (torrentCompleted (int)), this, SLOT (onTorrentCompleted (int))); 285 } 286 } 287 } 288 289 void 290 MyApp :: onTorrentCompleted (int id) 282 291 { 283 292 Torrent * tor = myModel->getTorrentFromId (id); … … 286 295 { 287 296 if (myPrefs->getBool (Prefs::SHOW_NOTIFICATION_ON_COMPLETE)) 288 notify (tr ("Torrent Completed"), tor->name());297 notify (tr ("Torrent Completed"), tor->name ()); 289 298 290 299 if (myPrefs->getBool (Prefs::COMPLETE_SOUND_ENABLED)) 291 300 { 292 #if defined ( Q_OS_WIN ) || defined( Q_OS_MAC)293 QApplication::beep ();301 #if defined (Q_OS_WIN) || defined (Q_OS_MAC) 302 QApplication::beep (); 294 303 #else 295 QProcess::execute (myPrefs->getString (Prefs::COMPLETE_SOUND_COMMAND));304 QProcess::execute (myPrefs->getString (Prefs::COMPLETE_SOUND_COMMAND)); 296 305 #endif 297 306 } 298 307 299 disconnect ( tor, SIGNAL(torrentCompleted(int)), this, SLOT(onTorrentCompleted(int)));300 } 301 } 302 303 void 304 MyApp :: onNewTorrentChanged ( int id)305 { 306 Torrent * tor = myModel->getTorrentFromId( id);307 308 if( tor && !tor->name().isEmpty())309 { 310 const int age_secs = tor->dateAdded().secsTo(QDateTime::currentDateTime());311 if( age_secs < 30)312 notify( tr( "Torrent Added" ), tor->name( ));313 314 disconnect( tor, SIGNAL(torrentChanged(int)), this, SLOT(onNewTorrentChanged(int)));315 316 if( !tor->isSeed( ))317 connect( tor, SIGNAL(torrentCompleted(int)), this, SLOT(onTorrentCompleted(int)));308 disconnect (tor, SIGNAL (torrentCompleted (int)), this, SLOT (onTorrentCompleted (int))); 309 } 310 } 311 312 void 313 MyApp :: onNewTorrentChanged (int id) 314 { 315 Torrent * tor = myModel->getTorrentFromId (id); 316 317 if (tor && !tor->name ().isEmpty ()) 318 { 319 const int age_secs = tor->dateAdded ().secsTo (QDateTime::currentDateTime ()); 320 if (age_secs < 30) 321 notify (tr ("Torrent Added"), tor->name ()); 322 323 disconnect (tor, SIGNAL (torrentChanged (int)), this, SLOT (onNewTorrentChanged (int))); 324 325 if (!tor->isSeed ()) 326 connect (tor, SIGNAL (torrentCompleted (int)), this, SLOT (onTorrentCompleted (int))); 318 327 } 319 328 } … … 324 333 325 334 void 326 MyApp :: consentGiven ()327 { 328 myPrefs->set<bool>( Prefs::USER_HAS_GIVEN_INFORMED_CONSENT, true);329 } 330 331 MyApp :: ~MyApp ()332 { 333 const QRect mainwinRect( myWindow->geometry( ));334 335 336 337 338 339 myPrefs->set( Prefs :: MAIN_WINDOW_HEIGHT, std::max( 100, mainwinRect.height( ) ));340 myPrefs->set( Prefs :: MAIN_WINDOW_WIDTH, std::max( 100, mainwinRect.width( ) ));341 myPrefs->set( Prefs :: MAIN_WINDOW_X, mainwinRect.x( ));342 myPrefs->set( Prefs :: MAIN_WINDOW_Y, mainwinRect.y( ));343 335 MyApp :: consentGiven () 336 { 337 myPrefs->set<bool> (Prefs::USER_HAS_GIVEN_INFORMED_CONSENT, true); 338 } 339 340 MyApp :: ~MyApp () 341 { 342 const QRect mainwinRect (myWindow->geometry ()); 343 delete myWatchDir; 344 delete myWindow; 345 delete myModel; 346 delete mySession; 347 348 myPrefs->set (Prefs :: MAIN_WINDOW_HEIGHT, std::max (100, mainwinRect.height ())); 349 myPrefs->set (Prefs :: MAIN_WINDOW_WIDTH, std::max (100, mainwinRect.width ())); 350 myPrefs->set (Prefs :: MAIN_WINDOW_X, mainwinRect.x ()); 351 myPrefs->set (Prefs :: MAIN_WINDOW_Y, mainwinRect.y ()); 352 delete myPrefs; 344 353 } 345 354 … … 349 358 350 359 void 351 MyApp :: refreshPref( int key ) 352 { 353 switch( key ) 354 { 355 case Prefs :: BLOCKLIST_UPDATES_ENABLED: 356 maybeUpdateBlocklist( ); 357 break; 358 359 case Prefs :: DIR_WATCH: 360 case Prefs :: DIR_WATCH_ENABLED: { 361 const QString path( myPrefs->getString( Prefs::DIR_WATCH ) ); 362 const bool isEnabled( myPrefs->getBool( Prefs::DIR_WATCH_ENABLED ) ); 363 myWatchDir->setPath( path, isEnabled ); 364 break; 360 MyApp :: refreshPref (int key) 361 { 362 switch (key) 363 { 364 case Prefs :: BLOCKLIST_UPDATES_ENABLED: 365 maybeUpdateBlocklist (); 366 break; 367 368 case Prefs :: DIR_WATCH: 369 case Prefs :: DIR_WATCH_ENABLED: 370 { 371 const QString path (myPrefs->getString (Prefs::DIR_WATCH)); 372 const bool isEnabled (myPrefs->getBool (Prefs::DIR_WATCH_ENABLED)); 373 myWatchDir->setPath (path, isEnabled); 374 break; 365 375 } 366 376 367 default: 368 break; 369 } 370 } 371 372 void 373 MyApp :: maybeUpdateBlocklist( ) 374 { 375 if( !myPrefs->getBool( Prefs :: BLOCKLIST_UPDATES_ENABLED ) ) 376 return; 377 378 const QDateTime lastUpdatedAt = myPrefs->getDateTime( Prefs :: BLOCKLIST_DATE ); 379 const QDateTime nextUpdateAt = lastUpdatedAt.addDays( 7 ); 380 const QDateTime now = QDateTime::currentDateTime( ); 381 if( now < nextUpdateAt ) 382 { 383 mySession->updateBlocklist( ); 384 myPrefs->set( Prefs :: BLOCKLIST_DATE, now ); 385 } 386 } 387 388 void 389 MyApp :: onSessionSourceChanged( ) 390 { 391 mySession->initTorrents( ); 392 mySession->refreshSessionStats( ); 393 mySession->refreshSessionInfo( ); 394 } 395 396 void 397 MyApp :: refreshTorrents( ) 398 { 399 // usually we just poll the torrents that have shown recent activity, 400 // but we also periodically ask for updates on the others to ensure 401 // nothing's falling through the cracks. 402 const time_t now = time( NULL ); 403 if( myLastFullUpdateTime + 60 >= now ) 404 mySession->refreshActiveTorrents( ); 405 else { 406 myLastFullUpdateTime = now; 407 mySession->refreshAllTorrents( ); 377 default: 378 break; 379 } 380 } 381 382 void 383 MyApp :: maybeUpdateBlocklist () 384 { 385 if (!myPrefs->getBool (Prefs :: BLOCKLIST_UPDATES_ENABLED)) 386 return; 387 388 const QDateTime lastUpdatedAt = myPrefs->getDateTime (Prefs :: BLOCKLIST_DATE); 389 const QDateTime nextUpdateAt = lastUpdatedAt.addDays (7); 390 const QDateTime now = QDateTime::currentDateTime (); 391 392 if (now < nextUpdateAt) 393 { 394 mySession->updateBlocklist (); 395 myPrefs->set (Prefs :: BLOCKLIST_DATE, now); 396 } 397 } 398 399 void 400 MyApp :: onSessionSourceChanged () 401 { 402 mySession->initTorrents (); 403 mySession->refreshSessionStats (); 404 mySession->refreshSessionInfo (); 405 } 406 407 void 408 MyApp :: refreshTorrents () 409 { 410 // usually we just poll the torrents that have shown recent activity, 411 // but we also periodically ask for updates on the others to ensure 412 // nothing's falling through the cracks. 413 const time_t now = time (NULL); 414 if (myLastFullUpdateTime + 60 >= now) 415 { 416 mySession->refreshActiveTorrents (); 417 } 418 else 419 { 420 myLastFullUpdateTime = now; 421 mySession->refreshAllTorrents (); 408 422 } 409 423 } … … 414 428 415 429 void 416 MyApp :: addTorrent ( const QString& key)417 { 418 const AddData addme( key);419 420 if( addme.type != addme.NONE)421 addTorrent( addme);422 } 423 424 void 425 MyApp :: addTorrent ( const AddData& addme)426 { 427 if( !myPrefs->getBool( Prefs :: OPTIONS_PROMPT ))428 { 429 mySession->addTorrent( addme);430 } 431 else if( addme.type == addme.URL)432 { 433 myWindow->openURL( addme.url.toString( ));434 } 435 else if( addme.type == addme.MAGNET)436 { 437 myWindow->openURL( addme.magnet);438 } 439 440 { 441 Options * o = new Options( *mySession, *myPrefs, addme, myWindow);442 o->show();443 } 444 445 raise();430 MyApp :: addTorrent (const QString& key) 431 { 432 const AddData addme (key); 433 434 if (addme.type != addme.NONE) 435 addTorrent (addme); 436 } 437 438 void 439 MyApp :: addTorrent (const AddData& addme) 440 { 441 if (!myPrefs->getBool (Prefs :: OPTIONS_PROMPT)) 442 { 443 mySession->addTorrent (addme); 444 } 445 else if (addme.type == addme.URL) 446 { 447 myWindow->openURL (addme.url.toString ()); 448 } 449 else if (addme.type == addme.MAGNET) 450 { 451 myWindow->openURL (addme.magnet); 452 } 453 else 454 { 455 Options * o = new Options (*mySession, *myPrefs, addme, myWindow); 456 o->show (); 457 } 458 459 raise (); 446 460 } 447 461 … … 451 465 452 466 void 453 MyApp :: raise ()454 { 455 QApplication :: alert ( myWindow);467 MyApp :: raise () 468 { 469 QApplication :: alert (myWindow); 456 470 } 457 471 458 472 bool 459 MyApp :: notify ( const QString& title, const QString& body) const460 { 461 const QString dbusServiceName = QString::fromAscii( "org.freedesktop.Notifications");462 const QString dbusInterfaceName = QString::fromAscii( "org.freedesktop.Notifications");463 const QString dbusPath = QString::fromAscii( "/org/freedesktop/Notifications");464 465 QDBusMessage m = QDBusMessage::createMethodCall(dbusServiceName, dbusPath, dbusInterfaceName, QString::fromAscii("Notify"));466 467 args.append( QString::fromAscii( "Transmission" )); // app_name468 args.append( 0U); // replaces_id469 args.append( QString::fromAscii( "transmission" )); // icon470 args.append( title); // summary471 args.append( body); // body472 args.append( QStringList( )); // actions - unused for plain passive popups473 args.append( QVariantMap( )); // hints - unused atm474 args.append( int32_t(-1)); // use the default timeout period475 m.setArguments( args);476 QDBusMessage replyMsg = QDBusConnection::sessionBus().call(m);477 //std::cerr << qPrintable(replyMsg.errorName()) << std::endl;478 //std::cerr << qPrintable(replyMsg.errorMessage()) << std::endl;479 return (replyMsg.type() == QDBusMessage::ReplyMessage) && !replyMsg.arguments().isEmpty();473 MyApp :: notify (const QString& title, const QString& body) const 474 { 475 const QString dbusServiceName = QString::fromAscii ("org.freedesktop.Notifications"); 476 const QString dbusInterfaceName = QString::fromAscii ("org.freedesktop.Notifications"); 477 const QString dbusPath = QString::fromAscii ("/org/freedesktop/Notifications"); 478 479 QDBusMessage m = QDBusMessage::createMethodCall (dbusServiceName, dbusPath, dbusInterfaceName, QString::fromAscii ("Notify")); 480 QList<QVariant> args; 481 args.append (QString::fromAscii ("Transmission")); // app_name 482 args.append (0U); // replaces_id 483 args.append (QString::fromAscii ("transmission")); // icon 484 args.append (title); // summary 485 args.append (body); // body 486 args.append (QStringList ()); // actions - unused for plain passive popups 487 args.append (QVariantMap ()); // hints - unused atm 488 args.append (int32_t (-1)); // use the default timeout period 489 m.setArguments (args); 490 QDBusMessage replyMsg = QDBusConnection::sessionBus ().call (m); 491 //std::cerr << qPrintable (replyMsg.errorName ()) << std::endl; 492 //std::cerr << qPrintable (replyMsg.errorMessage ()) << std::endl; 493 return (replyMsg.type () == QDBusMessage::ReplyMessage) && !replyMsg.arguments ().isEmpty (); 480 494 } 481 495 … … 485 499 486 500 int 487 main( int argc, char * argv[] ) 488 { 489 // find .torrents, URLs, magnet links, etc in the command-line args 490 int c; 491 QStringList addme; 492 const char * optarg; 493 char ** argvv = argv; 494 while( ( c = tr_getopt( getUsage( ), argc, (const char **)argvv, opts, &optarg ) ) ) 495 if( c == TR_OPT_UNK ) 496 addme.append( optarg ); 497 498 // try to delegate the work to an existing copy of Transmission 499 // before starting ourselves... 500 bool delegated = false; 501 QDBusConnection bus = QDBusConnection::sessionBus(); 502 for( int i=0, n=addme.size(); i<n; ++i ) 503 { 504 QDBusMessage request = QDBusMessage::createMethodCall( DBUS_SERVICE, 505 DBUS_OBJECT_PATH, 506 DBUS_INTERFACE, 507 QString::fromAscii("AddMetainfo") ); 508 QList<QVariant> arguments; 509 AddData a( addme[i] ); 510 switch( a.type ) { 511 case AddData::URL: arguments.push_back( a.url.toString( ) ); break; 512 case AddData::MAGNET: arguments.push_back( a.magnet ); break; 513 case AddData::FILENAME: arguments.push_back( a.toBase64().constData() ); break; 514 case AddData::METAINFO: arguments.push_back( a.toBase64().constData() ); break; 515 default: break; 501 main (int argc, char * argv[]) 502 { 503 // find .torrents, URLs, magnet links, etc in the command-line args 504 int c; 505 QStringList addme; 506 const char * optarg; 507 char ** argvv = argv; 508 while ( (c = tr_getopt (getUsage (), argc, (const char **)argvv, opts, &optarg))) 509 if (c == TR_OPT_UNK) 510 addme.append (optarg); 511 512 // try to delegate the work to an existing copy of Transmission 513 // before starting ourselves... 514 bool delegated = false; 515 QDBusConnection bus = QDBusConnection::sessionBus (); 516 for (int i=0, n=addme.size (); i<n; ++i) 517 { 518 QDBusMessage request = QDBusMessage::createMethodCall (DBUS_SERVICE, 519 DBUS_OBJECT_PATH, 520 DBUS_INTERFACE, 521 QString::fromAscii ("AddMetainfo")); 522 QList<QVariant> arguments; 523 AddData a (addme[i]); 524 switch (a.type) 525 { 526 case AddData::URL: arguments.push_back (a.url.toString ()); break; 527 case AddData::MAGNET: arguments.push_back (a.magnet); break; 528 case AddData::FILENAME: arguments.push_back (a.toBase64 ().constData ()); break; 529 case AddData::METAINFO: arguments.push_back (a.toBase64 ().constData ()); break; 530 default: break; 516 531 } 517 request.setArguments( arguments);518 519 QDBusMessage response = bus.call( request);520 //std::cerr << qPrintable(response.errorName()) << std::endl;521 //std::cerr << qPrintable(response.errorMessage()) << std::endl;522 arguments = response.arguments();523 delegated |= (arguments.size()==1) && arguments[0].toBool();524 } 525 526 if( delegated)527 528 529 530 MyApp app( argc, argv);531 return app.exec();532 } 532 request.setArguments (arguments); 533 534 QDBusMessage response = bus.call (request); 535 //std::cerr << qPrintable (response.errorName ()) << std::endl; 536 //std::cerr << qPrintable (response.errorMessage ()) << std::endl; 537 arguments = response.arguments (); 538 delegated |= (arguments.size ()==1) && arguments[0].toBool (); 539 } 540 541 if (delegated) 542 return 0; 543 544 tr_optind = 1; 545 MyApp app (argc, argv); 546 return app.exec (); 547 } -
trunk/qt/app.h
r12595 r13869 30 30 class MyApp: public QApplication 31 31 { 32 32 Q_OBJECT 33 33 34 35 MyApp( int& argc, char ** argv);36 virtual ~MyApp();34 public: 35 MyApp (int& argc, char ** argv); 36 virtual ~MyApp (); 37 37 38 39 void raise();40 bool notify( const QString& title, const QString& body) const;38 public: 39 void raise (); 40 bool notify (const QString& title, const QString& body) const; 41 41 42 43 42 public: 43 Favicons favicons; 44 44 45 46 47 48 49 50 51 52 53 54 55 56 45 private: 46 Prefs * myPrefs; 47 Session * mySession; 48 TorrentModel * myModel; 49 TrMainWindow * myWindow; 50 WatchDir * myWatchDir; 51 QTimer myModelTimer; 52 QTimer myStatsTimer; 53 QTimer mySessionTimer; 54 time_t myLastFullUpdateTime; 55 QTranslator qtTranslator; 56 QTranslator appTranslator; 57 57 58 59 void consentGiven();60 void onSessionSourceChanged();61 void refreshPref( int key);62 void refreshTorrents();63 void onTorrentsAdded( QSet<int>);64 void onTorrentCompleted( int);65 void onNewTorrentChanged( int);58 private slots: 59 void consentGiven (); 60 void onSessionSourceChanged (); 61 void refreshPref (int key); 62 void refreshTorrents (); 63 void onTorrentsAdded (QSet<int>); 64 void onTorrentCompleted (int); 65 void onNewTorrentChanged (int); 66 66 67 68 void addTorrent( const QString&);69 void addTorrent( const AddData&);67 public slots: 68 void addTorrent (const QString&); 69 void addTorrent (const AddData&); 70 70 71 72 void maybeUpdateBlocklist();71 private: 72 void maybeUpdateBlocklist (); 73 73 }; 74 74 -
trunk/qt/details.cc
r13868 r13869 45 45 46 46 #include <libtransmission/transmission.h> 47 #include <libtransmission/utils.h> // tr_getRatio ()47 #include <libtransmission/utils.h> // tr_getRatio () 48 48 49 49 #include "details.h" … … 71 71 const int REFRESH_INTERVAL_MSEC = 4000; 72 72 73 const char * PREF_KEY ( "pref-key");73 const char * PREF_KEY ("pref-key"); 74 74 75 75 enum // peer columns … … 97 97 98 98 public: 99 virtual ~PeerItem () { }100 PeerItem ( const Peer& p) {99 virtual ~PeerItem () { } 100 PeerItem (const Peer& p) { 101 101 peer = p; 102 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]);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 105 else 106 106 collatedAddress = p.address; 107 107 } 108 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) {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 116 case COL_UP: return peer.rateToPeer < i->peer.rateToPeer; 117 117 case COL_DOWN: return peer.rateToClient < i->peer.rateToClient; … … 130 130 131 131 QIcon 132 Details :: getStockIcon ( const QString& freedesktop_name, int fallback)133 { 134 QIcon icon = QIcon::fromTheme ( freedesktop_name);135 136 if ( icon.isNull( ))137 icon = style ()->standardIcon( QStyle::StandardPixmap( fallback ), 0, this);132 Details :: getStockIcon (const QString& freedesktop_name, int fallback) 133 { 134 QIcon icon = QIcon::fromTheme (freedesktop_name); 135 136 if (icon.isNull ()) 137 icon = style ()->standardIcon (QStyle::StandardPixmap (fallback), 0, this); 138 138 139 139 return icon; 140 140 } 141 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);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 155 QWidget * w; 156 t->addTab ( w = createInfoTab( ), tr( "Information" ));156 t->addTab (w = createInfoTab (), tr ("Information")); 157 157 myWidgets << w; 158 t->addTab ( w = createPeersTab( ), tr( "Peers" ));158 t->addTab (w = createPeersTab (), tr ("Peers")); 159 159 myWidgets << w; 160 t->addTab ( w = createTrackerTab( ), tr( "Tracker" ));160 t->addTab (w = createTrackerTab (), tr ("Tracker")); 161 161 myWidgets << w; 162 t->addTab ( w = createFilesTab( ), tr( "Files" ));162 t->addTab (w = createFilesTab (), tr ("Files")); 163 163 myWidgets << w; 164 t->addTab ( w = createOptionsTab( ), tr( "Options" ));164 t->addTab (w = createOptionsTab (), tr ("Options")); 165 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);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 172 173 173 QList<int> initKeys; 174 174 initKeys << Prefs :: SHOW_TRACKER_SCRAPES 175 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);185 } 186 187 Details :: ~Details ()188 { 189 myTrackerDelegate->deleteLater ();190 myTrackerFilter->deleteLater ();191 myTrackerModel->deleteLater ();192 } 193 194 void 195 Details :: setIds ( const QSet<int>& ids)196 { 197 if ( ids == myIds)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); 185 } 186 187 Details :: ~Details () 188 { 189 myTrackerDelegate->deleteLater (); 190 myTrackerFilter->deleteLater (); 191 myTrackerModel->deleteLater (); 192 } 193 194 void 195 Details :: setIds (const QSet<int>& ids) 196 { 197 if (ids == myIds) 198 198 return; 199 199 … … 201 201 202 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 disconnect ( tor, SIGNAL(torrentFileListRebuilt(int)), this, SLOT(onTorrentFileListRebuilt()));208 } 209 } 210 211 myFileTreeView->clear ();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 disconnect (tor, SIGNAL (torrentFileListRebuilt (int)), this, SLOT (onTorrentFileListRebuilt ())); 208 } 209 } 210 211 myFileTreeView->clear (); 212 212 myIds = ids; 213 myTrackerModel->refresh ( myModel, myIds);213 myTrackerModel->refresh (myModel, myIds); 214 214 215 215 // listen to the new torrents 216 foreach ( int id, myIds) {217 const Torrent * tor = myModel.getTorrentFromId ( id);218 if ( tor) {219 connect ( tor, SIGNAL(torrentChanged(int)), this, SLOT(onTorrentChanged()));220 connect ( tor, SIGNAL(torrentFileListRebuilt(int)), this, SLOT(onTorrentFileListRebuilt()));221 } 222 } 223 224 foreach ( QWidget * w, myWidgets)225 w->setEnabled ( false);226 227 onTimer ();228 } 229 230 void 231 Details :: refreshPref ( int key)216 foreach (int id, myIds) { 217 const Torrent * tor = myModel.getTorrentFromId (id); 218 if (tor) { 219 connect (tor, SIGNAL (torrentChanged (int)), this, SLOT (onTorrentChanged ())); 220 connect (tor, SIGNAL (torrentFileListRebuilt (int)), this, SLOT (onTorrentFileListRebuilt ())); 221 } 222 } 223 224 foreach (QWidget * w, myWidgets) 225 w->setEnabled (false); 226 227 onTimer (); 228 } 229 230 void 231 Details :: refreshPref (int key) 232 232 { 233 233 QString str; 234 234 235 switch ( key)235 switch (key) 236 236 { 237 237 case Prefs :: SHOW_TRACKER_SCRAPES: { 238 QItemSelectionModel * selectionModel ( myTrackerView->selectionModel( ));239 const QItemSelection selection ( selectionModel->selection( ));240 const QModelIndex currentIndex ( selectionModel->currentIndex( ));241 myTrackerDelegate->setShowMore ( myPrefs.getBool( key ));242 selectionModel->clear ();243 myTrackerView->reset ();244 selectionModel->select ( selection, QItemSelectionModel::Select);245 selectionModel->setCurrentIndex ( currentIndex, QItemSelectionModel::NoUpdate);238 QItemSelectionModel * selectionModel (myTrackerView->selectionModel ()); 239 const QItemSelection selection (selectionModel->selection ()); 240 const QModelIndex currentIndex (selectionModel->currentIndex ()); 241 myTrackerDelegate->setShowMore (myPrefs.getBool (key)); 242 selectionModel->clear (); 243 myTrackerView->reset (); 244 selectionModel->select (selection, QItemSelectionModel::Select); 245 selectionModel->setCurrentIndex (currentIndex, QItemSelectionModel::NoUpdate); 246 246 break; 247 247 } 248 248 249 249 case Prefs :: SHOW_BACKUP_TRACKERS: 250 myTrackerFilter->setShowBackupTrackers ( myPrefs.getBool( key ));250 myTrackerFilter->setShowBackupTrackers (myPrefs.getBool (key)); 251 251 break; 252 252 … … 262 262 263 263 QString 264 Details :: timeToStringRounded ( int seconds)265 { 266 if ( seconds > 60 ) seconds -= ( seconds % 60);267 return Formatter::timeToString ( seconds);268 } 269 270 void 271 Details :: onTimer ()272 { 273 getNewData ();274 } 275 276 void 277 Details :: getNewData ()278 { 279 if ( !myIds.empty( ))264 Details :: timeToStringRounded (int seconds) 265 { 266 if (seconds > 60) seconds -= (seconds % 60); 267 return Formatter::timeToString (seconds); 268 } 269 270 void 271 Details :: onTimer () 272 { 273 getNewData (); 274 } 275 276 void 277 Details :: getNewData () 278 { 279 if (!myIds.empty ()) 280 280 { 281 281 QSet<int> infos; 282 foreach ( int id, myIds) {283 const Torrent * tor = myModel.getTorrentFromId ( id);284 if ( tor->isMagnet())285 infos.insert ( tor->id());286 } 287 if ( !infos.isEmpty())288 mySession.initTorrents ( infos);289 mySession.refreshExtraStats ( myIds);290 } 291 } 292 293 void 294 Details :: onTorrentChanged ()295 { 296 if ( !myHavePendingRefresh) {282 foreach (int id, myIds) { 283 const Torrent * tor = myModel.getTorrentFromId (id); 284 if (tor->isMagnet ()) 285 infos.insert (tor->id ()); 286 } 287 if (!infos.isEmpty ()) 288 mySession.initTorrents (infos); 289 mySession.refreshExtraStats (myIds); 290 } 291 } 292 293 void 294 Details :: onTorrentChanged () 295 { 296 if (!myHavePendingRefresh) { 297 297 myHavePendingRefresh = true; 298 QTimer::singleShot ( 100, this, SLOT(refresh()));299 } 300 } 301 302 void 303 Details :: onTorrentFileListRebuilt ()298 QTimer::singleShot (100, this, SLOT (refresh ())); 299 } 300 } 301 302 void 303 Details :: onTorrentFileListRebuilt () 304 304 { 305 305 myFilesDirty = true; 306 onTorrentChanged ();306 onTorrentChanged (); 307 307 } 308 308 309 309 namespace 310 310 { 311 void setIfIdle ( QComboBox * box, int i)312 { 313 if ( !box->hasFocus( ))311 void setIfIdle (QComboBox * box, int i) 312 { 313 if (!box->hasFocus ()) 314 314 { 315 box->blockSignals ( true);316 box->setCurrentIndex ( i);317 box->blockSignals ( false);318 } 319 } 320 321 void setIfIdle ( QDoubleSpinBox * spin, double value)322 { 323 if ( !spin->hasFocus( ))315 box->blockSignals (true); 316 box->setCurrentIndex (i); 317 box->blockSignals (false); 318 } 319 } 320 321 void setIfIdle (QDoubleSpinBox * spin, double value) 322 { 323 if (!spin->hasFocus ()) 324 324 { 325 spin->blockSignals ( true);326 spin->setValue ( value);327 spin->blockSignals ( false);328 } 329 } 330 331 void setIfIdle ( QSpinBox * spin, int value)332 { 333 if ( !spin->hasFocus( ))325 spin->blockSignals (true); 326 spin->setValue (value); 327 spin->blockSignals (false); 328 } 329 } 330 331 void setIfIdle (QSpinBox * spin, int value) 332 { 333 if (!spin->hasFocus ()) 334 334 { 335 spin->blockSignals ( true);336 spin->setValue ( value);337 spin->blockSignals ( false);338 } 339 } 340 } 341 342 void 343 Details :: refresh ()344 { 345 const int n = myIds.size ();335 spin->blockSignals (true); 336 spin->setValue (value); 337 spin->blockSignals (false); 338 } 339 } 340 } 341 342 void 343 Details :: refresh () 344 { 345 const int n = myIds.size (); 346 346 const bool single = n == 1; 347 347 const QString blank; 348 const QFontMetrics fm ( fontMetrics( ));348 const QFontMetrics fm (fontMetrics ()); 349 349 QList<const Torrent*> torrents; 350 350 QString string; 351 const QString none = tr ( "None");352 const QString mixed = tr ( "Mixed");353 const QString unknown = tr ( "Unknown");351 const QString none = tr ("None"); 352 const QString mixed = tr ("Mixed"); 353 const QString unknown = tr ("Unknown"); 354 354 355 355 // build a list of torrents 356 foreach ( int id, myIds) {357 const Torrent * tor = myModel.getTorrentFromId ( id);358 if ( tor)356 foreach (int id, myIds) { 357 const Torrent * tor = myModel.getTorrentFromId (id); 358 if (tor) 359 359 torrents << tor; 360 360 } … … 365 365 366 366 // myStateLabel 367 if ( torrents.empty( ))367 if (torrents.empty ()) 368 368 string = none; 369 369 else { … … 371 371 bool allPaused = true; 372 372 bool allFinished = true; 373 const tr_torrent_activity baseline = torrents[0]->getActivity ();374 foreach ( const Torrent * t, torrents) {375 const tr_torrent_activity activity = t->getActivity ();376 if ( activity != baseline)373 const tr_torrent_activity baseline = torrents[0]->getActivity (); 374 foreach (const Torrent * t, torrents) { 375 const tr_torrent_activity activity = t->getActivity (); 376 if (activity != baseline) 377 377 isMixed = true; 378 if ( activity != TR_STATUS_STOPPED)378 if (activity != TR_STATUS_STOPPED) 379 379 allPaused = allFinished = false; 380 if ( !t->isFinished( ))380 if (!t->isFinished ()) 381 381 allFinished = false; 382 382 } 383 if ( isMixed)383 if (isMixed) 384 384 string = mixed; 385 else if ( allFinished)386 string = tr ( "Finished");387 else if ( allPaused)388 string = tr ( "Paused");385 else if (allFinished) 386 string = tr ("Finished"); 387 else if (allPaused) 388 string = tr ("Paused"); 389 389 else 390 string = torrents[0]->activityString ();391 } 392 myStateLabel->setText ( string);390 string = torrents[0]->activityString (); 391 } 392 myStateLabel->setText (string); 393 393 const QString stateString = string; 394 394 … … 401 401 int64_t haveUnverified = 0; 402 402 int64_t verifiedPieces = 0; 403 if ( torrents.empty( ))404 string = none; 405 else { 406 foreach ( const Torrent * t, torrents) {407 if ( t->hasMetadata( )) {408 haveTotal += t->haveTotal ();409 haveUnverified += t->haveUnverified ();410 const uint64_t v = t->haveVerified ();403 if (torrents.empty ()) 404 string = none; 405 else { 406 foreach (const Torrent * t, torrents) { 407 if (t->hasMetadata ()) { 408 haveTotal += t->haveTotal (); 409 haveUnverified += t->haveUnverified (); 410 const uint64_t v = t->haveVerified (); 411 411 haveVerified += v; 412 if ( t->pieceSize( ))413 verifiedPieces += v / t->pieceSize ();414 sizeWhenDone += t->sizeWhenDone ();415 leftUntilDone += t->leftUntilDone ();416 available += t->sizeWhenDone () - t->leftUntilDone() + t->desiredAvailable();412 if (t->pieceSize ()) 413 verifiedPieces += v / t->pieceSize (); 414 sizeWhenDone += t->sizeWhenDone (); 415 leftUntilDone += t->leftUntilDone (); 416 available += t->sizeWhenDone () - t->leftUntilDone () + t->desiredAvailable (); 417 417 } 418 418 } 419 419 { 420 const double d = 100.0 * ( sizeWhenDone ? ( sizeWhenDone - leftUntilDone ) / sizeWhenDone : 1);421 QString pct = Formatter::percentToString ( d);422 423 if ( !haveUnverified && !leftUntilDone)420 const double d = 100.0 * (sizeWhenDone ? (sizeWhenDone - leftUntilDone) / sizeWhenDone : 1); 421 QString pct = Formatter::percentToString (d); 422 423 if (!haveUnverified && !leftUntilDone) 424 424 { 425 string = tr ( "%1 (100%)")426 .arg ( Formatter::sizeToString( haveVerified ));425 string = tr ("%1 (100%)") 426 .arg (Formatter::sizeToString (haveVerified)); 427 427 } 428 else if ( !haveUnverified)428 else if (!haveUnverified) 429 429 { 430 string = tr ( "%1 of %2 (%3%)")431 .arg ( Formatter::sizeToString( haveVerified ))432 .arg ( Formatter::sizeToString( sizeWhenDone ))433 .arg ( pct);430 string = tr ("%1 of %2 (%3%)") 431 .arg (Formatter::sizeToString (haveVerified)) 432 .arg (Formatter::sizeToString (sizeWhenDone)) 433 .arg (pct); 434 434 } 435 435 else 436 436 { 437 string = tr ( "%1 of %2 (%3%), %4 Unverified")438 .arg ( Formatter::sizeToString( haveVerified + haveUnverified ))439 .arg ( Formatter::sizeToString( sizeWhenDone ))440 .arg ( pct)441 .arg ( Formatter::sizeToString( haveUnverified ));437 string = tr ("%1 of %2 (%3%), %4 Unverified") 438 .arg (Formatter::sizeToString (haveVerified + haveUnverified)) 439 .arg (Formatter::sizeToString (sizeWhenDone)) 440 .arg (pct) 441 .arg (Formatter::sizeToString (haveUnverified)); 442 442 } 443 443 } 444 444 } 445 myHaveLabel->setText ( string);445 myHaveLabel->setText (string); 446 446 447 447 // myAvailabilityLabel 448 if ( torrents.empty( ))449 string = none; 450 else { 451 if ( sizeWhenDone == 0)448 if (torrents.empty ()) 449 string = none; 450 else { 451 if (sizeWhenDone == 0) 452 452 string = none; 453 453 else 454 string = QString ( "%1%" ).arg( Formatter::percentToString( ( 100.0 * available ) / sizeWhenDone ));455 } 456 myAvailabilityLabel->setText ( string);454 string = QString ("%1%").arg (Formatter::percentToString ( (100.0 * available) / sizeWhenDone)); 455 } 456 myAvailabilityLabel->setText (string); 457 457 458 458 // myDownloadedLabel 459 if ( torrents.empty( ))459 if (torrents.empty ()) 460 460 string = none; 461 461 else { 462 462 uint64_t d = 0; 463 463 uint64_t f = 0; 464 foreach ( const Torrent * t, torrents) {465 d += t->downloadedEver ();466 f += t->failedEver ();467 } 468 const QString dstr = Formatter::sizeToString ( d);469 const QString fstr = Formatter::sizeToString ( f);470 if ( f)471 string = tr ( "%1 (%2 corrupt)" ).arg( dstr ).arg( fstr);464 foreach (const Torrent * t, torrents) { 465 d += t->downloadedEver (); 466 f += t->failedEver (); 467 } 468 const QString dstr = Formatter::sizeToString (d); 469 const QString fstr = Formatter::sizeToString (f); 470 if (f) 471 string = tr ("%1 (%2 corrupt)").arg (dstr).arg (fstr); 472 472 else 473 473 string = dstr; 474 474 } 475 myDownloadedLabel->setText ( string);476 477 if ( torrents.empty( ))475 myDownloadedLabel->setText (string); 476 477 if (torrents.empty ()) 478 478 string = none; 479 479 else { 480 480 uint64_t u = 0; 481 481 uint64_t d = 0; 482 foreach ( const Torrent * t, torrents) {483 u += t->uploadedEver ();484 d += t->downloadedEver ();485 } 486 string = tr ( "%1 (Ratio: %2)")487 .arg ( Formatter::sizeToString( u ))488 .arg ( Formatter::ratioToString( tr_getRatio( u, d ) ));489 } 490 myUploadedLabel->setText ( string);491 492 const QDateTime qdt_now = QDateTime::currentDateTime ();482 foreach (const Torrent * t, torrents) { 483 u += t->uploadedEver (); 484 d += t->downloadedEver (); 485 } 486 string = tr ("%1 (Ratio: %2)") 487 .arg (Formatter::sizeToString (u)) 488 .arg (Formatter::ratioToString (tr_getRatio (u, d))); 489 } 490 myUploadedLabel->setText (string); 491 492 const QDateTime qdt_now = QDateTime::currentDateTime (); 493 493 494 494 // myRunTimeLabel 495 if ( torrents.empty( ))495 if (torrents.empty ()) 496 496 string = none; 497 497 else { 498 498 bool allPaused = true; 499 QDateTime baseline = torrents[0]->lastStarted ();500 foreach ( const Torrent * t, torrents) {501 if ( baseline != t->lastStarted( ))502 baseline = QDateTime ();503 if ( !t->isPaused( ))499 QDateTime baseline = torrents[0]->lastStarted (); 500 foreach (const Torrent * t, torrents) { 501 if (baseline != t->lastStarted ()) 502 baseline = QDateTime (); 503 if (!t->isPaused ()) 504 504 allPaused = false; 505 505 } 506 if ( allPaused)506 if (allPaused) 507 507 string = stateString; // paused || finished 508 else if ( baseline.isNull( ))508 else if (baseline.isNull ()) 509 509 string = mixed; 510 510 else 511 string = Formatter::timeToString ( baseline.secsTo( qdt_now ));512 } 513 myRunTimeLabel->setText ( string);511 string = Formatter::timeToString (baseline.secsTo (qdt_now)); 512 } 513 myRunTimeLabel->setText (string); 514 514 515 515 516 516 // myETALabel 517 string.clear ();518 if ( torrents.empty( ))519 string = none; 520 else { 521 int baseline = torrents[0]->getETA ();522 foreach ( const Torrent * t, torrents) {523 if ( baseline != t->getETA( )) {517 string.clear (); 518 if (torrents.empty ()) 519 string = none; 520 else { 521 int baseline = torrents[0]->getETA (); 522 foreach (const Torrent * t, torrents) { 523 if (baseline != t->getETA ()) { 524 524 string = mixed; 525 525 break; 526 526 } 527 527 } 528 if ( string.isEmpty( )) {529 if ( baseline < 0)530 string = tr ( "Unknown");528 if (string.isEmpty ()) { 529 if (baseline < 0) 530 string = tr ("Unknown"); 531 531 else 532 string = Formatter::timeToString ( baseline);532 string = Formatter::timeToString (baseline); 533 533 } 534 534 } 535 myETALabel->setText ( string);535 myETALabel->setText (string); 536 536 537 537 538 538 // myLastActivityLabel 539 if ( torrents.empty( ))540 string = none; 541 else { 542 QDateTime latest = torrents[0]->lastActivity ();543 foreach ( const Torrent * t, torrents) {544 const QDateTime dt = t->lastActivity ();545 if ( latest < dt)539 if (torrents.empty ()) 540 string = none; 541 else { 542 QDateTime latest = torrents[0]->lastActivity (); 543 foreach (const Torrent * t, torrents) { 544 const QDateTime dt = t->lastActivity (); 545 if (latest < dt) 546 546 latest = dt; 547 547 } 548 const int seconds = latest.isValid () ? latest.secsTo( qdt_now) : -1;549 if ( seconds < 0)548 const int seconds = latest.isValid () ? latest.secsTo (qdt_now) : -1; 549 if (seconds < 0) 550 550 string = none; 551 else if ( seconds < 5)552 string = tr ( "Active now");551 else if (seconds < 5) 552 string = tr ("Active now"); 553 553 else 554 string = tr ( "%1 ago" ).arg( Formatter::timeToString( seconds ));555 } 556 myLastActivityLabel->setText ( string);557 558 559 if ( torrents.empty( ))560 string = none; 561 else { 562 string = torrents[0]->getError ();563 foreach ( const Torrent * t, torrents) {564 if ( string != t->getError( )) {554 string = tr ("%1 ago").arg (Formatter::timeToString (seconds)); 555 } 556 myLastActivityLabel->setText (string); 557 558 559 if (torrents.empty ()) 560 string = none; 561 else { 562 string = torrents[0]->getError (); 563 foreach (const Torrent * t, torrents) { 564 if (string != t->getError ()) { 565 565 string = mixed; 566 566 break; … … 568 568 } 569 569 } 570 if ( string.isEmpty( ))571 string = none; 572 myErrorLabel->setText ( string);570 if (string.isEmpty ()) 571 string = none; 572 myErrorLabel->setText (string); 573 573 574 574 … … 578 578 579 579 // mySizeLabel 580 if ( torrents.empty( ))580 if (torrents.empty ()) 581 581 string = none; 582 582 else { 583 583 int pieces = 0; 584 584 uint64_t size = 0; 585 uint32_t pieceSize = torrents[0]->pieceSize ();586 foreach ( const Torrent * t, torrents) {587 pieces += t->pieceCount ();588 size += t->totalSize ();589 if ( pieceSize != t->pieceSize( ))585 uint32_t pieceSize = torrents[0]->pieceSize (); 586 foreach (const Torrent * t, torrents) { 587 pieces += t->pieceCount (); 588 size += t->totalSize (); 589 if (pieceSize != t->pieceSize ()) 590 590 pieceSize = 0; 591 591 } 592 if ( !size)592 if (!size) 593 593 string = none; 594 else if ( pieceSize > 0)595 string = tr ( "%1 (%Ln pieces @ %2)", "", pieces)596 .arg ( Formatter::sizeToString( size ))597 .arg ( Formatter::memToString( pieceSize ));594 else if (pieceSize > 0) 595 string = tr ("%1 (%Ln pieces @ %2)", "", pieces) 596 .arg (Formatter::sizeToString (size)) 597 .arg (Formatter::memToString (pieceSize)); 598 598 else 599 string = tr ( "%1 (%Ln pieces)", "", pieces)600 .arg ( Formatter::sizeToString( size ));601 } 602 mySizeLabel->setText ( string);599 string = tr ("%1 (%Ln pieces)", "", pieces) 600 .arg (Formatter::sizeToString (size)); 601 } 602 mySizeLabel->setText (string); 603 603 604 604 // myHashLabel 605 if ( torrents.empty( ))606 string = none; 607 else { 608 string = torrents[0]->hashString ();609 foreach ( const Torrent * t, torrents) {610 if ( string != t->hashString( )) {605 if (torrents.empty ()) 606 string = none; 607 else { 608 string = torrents[0]->hashString (); 609 foreach (const Torrent * t, torrents) { 610 if (string != t->hashString ()) { 611 611 string = mixed; 612 612 break; … … 614 614 } 615 615 } 616 myHashLabel->setText ( string);616 myHashLabel->setText (string); 617 617 618 618 // myPrivacyLabel 619 if ( torrents.empty( ))620 string = none; 621 else { 622 bool b = torrents[0]->isPrivate ();623 string = b ? tr ( "Private to this tracker -- DHT and PEX disabled")624 : tr ( "Public torrent");625 foreach ( const Torrent * t, torrents) {626 if ( b != t->isPrivate( )) {619 if (torrents.empty ()) 620 string = none; 621 else { 622 bool b = torrents[0]->isPrivate (); 623 string = b ? tr ("Private to this tracker -- DHT and PEX disabled") 624 : tr ("Public torrent"); 625 foreach (const Torrent * t, torrents) { 626 if (b != t->isPrivate ()) { 627 627 string = mixed; 628 628 break; … … 630 630 } 631 631 } 632 myPrivacyLabel->setText ( string);632 myPrivacyLabel->setText (string); 633 633 634 634 // myCommentBrowser 635 if ( torrents.empty( ))636 string = none; 637 else { 638 string = torrents[0]->comment ();639 foreach ( const Torrent * t, torrents) {640 if ( string != t->comment( )) {635 if (torrents.empty ()) 636 string = none; 637 else { 638 string = torrents[0]->comment (); 639 foreach (const Torrent * t, torrents) { 640 if (string != t->comment ()) { 641 641 string = mixed; 642 642 break; … … 644 644 } 645 645 } 646 myCommentBrowser->setText ( string);647 myCommentBrowser->setMaximumHeight ( QWIDGETSIZE_MAX);646 myCommentBrowser->setText (string); 647 myCommentBrowser->setMaximumHeight (QWIDGETSIZE_MAX); 648 648 649 649 // myOriginLabel 650 if ( torrents.empty( ))650 if (torrents.empty ()) 651 651 string = none; 652 652 else { 653 653 bool mixed_creator=false, mixed_date=false; 654 const QString creator = torrents[0]->creator ();655 const QString date = torrents[0]->dateCreated ().toString();656 foreach ( const Torrent * t, torrents) {657 mixed_creator |= ( creator != t->creator());658 mixed_date |= ( date != t->dateCreated().toString());659 } 660 if ( mixed_creator && mixed_date)654 const QString creator = torrents[0]->creator (); 655 const QString date = torrents[0]->dateCreated ().toString (); 656 foreach (const Torrent * t, torrents) { 657 mixed_creator |= (creator != t->creator ()); 658 mixed_date |= (date != t->dateCreated ().toString ()); 659 } 660 if (mixed_creator && mixed_date) 661 661 string = mixed; 662 else if ( mixed_date && !creator.isEmpty())663 string = tr ( "Created by %1" ).arg( creator);664 else if ( mixed_creator && !date.isEmpty())665 string = tr ( "Created on %1" ).arg( date);666 else if ( creator.isEmpty() && date.isEmpty())667 string = tr ( "N/A");662 else if (mixed_date && !creator.isEmpty ()) 663 string = tr ("Created by %1").arg (creator); 664 else if (mixed_creator && !date.isEmpty ()) 665 string = tr ("Created on %1").arg (date); 666 else if (creator.isEmpty () && date.isEmpty ()) 667 string = tr ("N/A"); 668 668 else 669 string = tr ( "Created by %1 on %2" ).arg( creator ).arg( date);670 } 671 myOriginLabel->setText ( string);669 string = tr ("Created by %1 on %2").arg (creator).arg (date); 670 } 671 myOriginLabel->setText (string); 672 672 673 673 // myLocationLabel 674 if ( torrents.empty( ))675 string = none; 676 else { 677 string = torrents[0]->getPath ();678 foreach ( const Torrent * t, torrents) {679 if ( string != t->getPath( )) {674 if (torrents.empty ()) 675 string = none; 676 else { 677 string = torrents[0]->getPath (); 678 foreach (const Torrent * t, torrents) { 679 if (string != t->getPath ()) { 680 680 string = mixed; 681 681 break; … … 683 683 } 684 684 } 685 myLocationLabel->setText ( string);685 myLocationLabel->setText (string); 686 686 687 687 … … 690 690 /// 691 691 692 if ( myChangedTorrents && !torrents.empty( ))692 if (myChangedTorrents && !torrents.empty ()) 693 693 { 694 694 int i; 695 const Torrent * baseline = *torrents.begin ();695 const Torrent * baseline = *torrents.begin (); 696 696 const Torrent * tor; 697 697 bool uniform; … … 701 701 // mySessionLimitCheck 702 702 uniform = true; 703 baselineFlag = baseline->honorsSessionLimits ();704 foreach ( tor, torrents ) if( baselineFlag != tor->honorsSessionLimits( )) { uniform = false; break; }705 mySessionLimitCheck->setChecked ( uniform && baselineFlag);703 baselineFlag = baseline->honorsSessionLimits (); 704 foreach (tor, torrents) if (baselineFlag != tor->honorsSessionLimits ()) { uniform = false; break; } 705 mySessionLimitCheck->setChecked (uniform && baselineFlag); 706 706 707 707 // mySingleDownCheck 708 708 uniform = true; 709 baselineFlag = baseline->downloadIsLimited ();710 foreach ( tor, torrents ) if( baselineFlag != tor->downloadIsLimited( )) { uniform = false; break; }711 mySingleDownCheck->setChecked ( uniform && baselineFlag);709 baselineFlag = baseline->downloadIsLimited (); 710 foreach (tor, torrents) if (baselineFlag != tor->downloadIsLimited ()) { uniform = false; break; } 711 mySingleDownCheck->setChecked (uniform && baselineFlag); 712 712 713 713 // mySingleUpCheck 714 714 uniform = true; 715 baselineFlag = baseline->uploadIsLimited ();716 foreach ( tor, torrents ) if( baselineFlag != tor->uploadIsLimited( )) { uniform = false; break; }717 mySingleUpCheck->setChecked ( uniform && baselineFlag);715 baselineFlag = baseline->uploadIsLimited (); 716 foreach (tor, torrents) if (baselineFlag != tor->uploadIsLimited ()) { uniform = false; break; } 717 mySingleUpCheck->setChecked (uniform && baselineFlag); 718 718 719 719 // myBandwidthPriorityCombo 720 720 uniform = true; 721 baselineInt = baseline->getBandwidthPriority ();722 foreach ( tor, torrents ) if ( baselineInt != tor->getBandwidthPriority( )) { uniform = false; break; }723 if ( uniform)724 i = myBandwidthPriorityCombo->findData ( baselineInt);721 baselineInt = baseline->getBandwidthPriority (); 722 foreach (tor, torrents) if (baselineInt != tor->getBandwidthPriority ()) { uniform = false; break; } 723 if (uniform) 724 i = myBandwidthPriorityCombo->findData (baselineInt); 725 725 else 726 726 i = -1; 727 setIfIdle ( myBandwidthPriorityCombo, i);728 729 setIfIdle ( mySingleDownSpin, int(tor->downloadLimit().KBps()));730 setIfIdle ( mySingleUpSpin, int(tor->uploadLimit().KBps()));731 setIfIdle ( myPeerLimitSpin, tor->peerLimit());732 } 733 734 if ( !torrents.empty( ))727 setIfIdle (myBandwidthPriorityCombo, i); 728 729 setIfIdle (mySingleDownSpin, int (tor->downloadLimit ().KBps ())); 730 setIfIdle (mySingleUpSpin, int (tor->uploadLimit ().KBps ())); 731 setIfIdle (myPeerLimitSpin, tor->peerLimit ()); 732 } 733 734 if (!torrents.empty ()) 735 735 { 736 736 const Torrent * tor; … … 738 738 // ratio 739 739 bool uniform = true; 740 int baselineInt = torrents[0]->seedRatioMode ();741 foreach ( tor, torrents ) if( baselineInt != tor->seedRatioMode( )) { uniform = false; break; }742 743 setIfIdle ( myRatioCombo, uniform ? myRatioCombo->findData( baselineInt ) : -1);744 myRatioSpin->setVisible ( uniform && ( baselineInt == TR_RATIOLIMIT_SINGLE ));745 746 setIfIdle ( myRatioSpin, tor->seedRatioLimit( ));740 int baselineInt = torrents[0]->seedRatioMode (); 741 foreach (tor, torrents) if (baselineInt != tor->seedRatioMode ()) { uniform = false; break; } 742 743 setIfIdle (myRatioCombo, uniform ? myRatioCombo->findData (baselineInt) : -1); 744 myRatioSpin->setVisible (uniform && (baselineInt == TR_RATIOLIMIT_SINGLE)); 745 746 setIfIdle (myRatioSpin, tor->seedRatioLimit ()); 747 747 748 748 // idle 749 749 uniform = true; 750 baselineInt = torrents[0]->seedIdleMode ();751 foreach ( tor, torrents ) if( baselineInt != tor->seedIdleMode( )) { uniform = false; break; }752 753 setIfIdle ( myIdleCombo, uniform ? myIdleCombo->findData( baselineInt ) : -1);754 myIdleSpin->setVisible ( uniform && ( baselineInt == TR_RATIOLIMIT_SINGLE ));755 756 setIfIdle ( myIdleSpin, tor->seedIdleLimit( ));750 baselineInt = torrents[0]->seedIdleMode (); 751 foreach (tor, torrents) if (baselineInt != tor->seedIdleMode ()) { uniform = false; break; } 752 753 setIfIdle (myIdleCombo, uniform ? myIdleCombo->findData (baselineInt) : -1); 754 myIdleSpin->setVisible (uniform && (baselineInt == TR_RATIOLIMIT_SINGLE)); 755 756 setIfIdle (myIdleSpin, tor->seedIdleLimit ()); 757 757 } 758 758 … … 761 761 /// 762 762 763 myTrackerModel->refresh ( myModel, myIds);763 myTrackerModel->refresh (myModel, myIds); 764 764 765 765 /// … … 769 769 QMap<QString,QTreeWidgetItem*> peers2; 770 770 QList<QTreeWidgetItem*> newItems; 771 foreach ( const Torrent * t, torrents)772 { 773 const QString idStr ( QString::number( t->id( ) ));774 PeerList peers = t->peers ();775 776 foreach ( const Peer& peer, peers)771 foreach (const Torrent * t, torrents) 772 { 773 const QString idStr (QString::number (t->id ())); 774 PeerList peers = t->peers (); 775 776 foreach (const Peer& peer, peers) 777 777 { 778 778 const QString key = idStr + ":" + peer.address; 779 PeerItem * item = (PeerItem*) myPeers.value ( key, 0);780 781 if ( item == 0) // new peer has connected779 PeerItem * item = (PeerItem*) myPeers.value (key, 0); 780 781 if (item == 0) // new peer has connected 782 782 { 783 static const QIcon myEncryptionIcon ( ":/icons/encrypted.png");783 static const QIcon myEncryptionIcon (":/icons/encrypted.png"); 784 784 static const QIcon myEmptyIcon; 785 item = new PeerItem ( peer);786 item->setTextAlignment ( COL_UP, Qt::AlignRight|Qt::AlignVCenter);787 item->setTextAlignment ( COL_DOWN, Qt::AlignRight|Qt::AlignVCenter);788 item->setTextAlignment ( COL_PERCENT, Qt::AlignRight|Qt::AlignVCenter);789 item->setIcon ( COL_LOCK, peer.isEncrypted ? myEncryptionIcon : myEmptyIcon);790 item->setToolTip ( COL_LOCK, peer.isEncrypted ? tr( "Encrypted connection" ) : "");791 item->setText ( COL_ADDRESS, peer.address);792 item->setText ( COL_CLIENT, peer.clientName);785 item = new PeerItem (peer); 786 item->setTextAlignment (COL_UP, Qt::AlignRight|Qt::AlignVCenter); 787 item->setTextAlignment (COL_DOWN, Qt::AlignRight|Qt::AlignVCenter); 788 item->setTextAlignment (COL_PERCENT, Qt::AlignRight|Qt::AlignVCenter); 789 item->setIcon (COL_LOCK, peer.isEncrypted ? myEncryptionIcon : myEmptyIcon); 790 item->setToolTip (COL_LOCK, peer.isEncrypted ? tr ("Encrypted connection") : ""); 791 item->setText (COL_ADDRESS, peer.address); 792 item->setText (COL_CLIENT, peer.clientName); 793 793 newItems << item; 794 794 } 795 795 796 796 const QString code = peer.flagStr; 797 item->setStatus ( code);798 item->refresh ( peer);797 item->setStatus (code); 798 item->refresh (peer); 799 799 800 800 QString codeTip; 801 foreach ( QChar ch, code) {801 foreach (QChar ch, code) { 802 802 QString txt; 803 switch ( ch.toAscii()) {804 case 'O': txt = tr ( "Optimistic unchoke"); break;805 case 'D': txt = tr ( "Downloading from this peer"); break;806 case 'd': txt = tr ( "We would download from this peer if they would let us"); break;807 case 'U': txt = tr ( "Uploading to peer"); break;808 case 'u': txt = tr ( "We would upload to this peer if they asked"); break;809 case 'K': txt = tr ( "Peer has unchoked us, but we're not interested"); break;810 case '?': txt = tr ( "We unchoked this peer, but they're not interested"); break;811 case 'E': txt = tr ( "Encrypted connection"); break;812 case 'H': txt = tr ( "Peer was discovered through DHT"); break;813 case 'X': txt = tr ( "Peer was discovered through Peer Exchange (PEX)"); break;814 case 'I': txt = tr ( "Peer is an incoming connection"); break;815 case 'T': txt = tr ( "Peer is connected over uTP"); break;803 switch (ch.toAscii ()) { 804 case 'O': txt = tr ("Optimistic unchoke"); break; 805 case 'D': txt = tr ("Downloading from this peer"); break; 806 case 'd': txt = tr ("We would download from this peer if they would let us"); break; 807 case 'U': txt = tr ("Uploading to peer"); break; 808 case 'u': txt = tr ("We would upload to this peer if they asked"); break; 809 case 'K': txt = tr ("Peer has unchoked us, but we're not interested"); break; 810 case '?': txt = tr ("We unchoked this peer, but they're not interested"); break; 811 case 'E': txt = tr ("Encrypted connection"); break; 812 case 'H': txt = tr ("Peer was discovered through DHT"); break; 813 case 'X': txt = tr ("Peer was discovered through Peer Exchange (PEX)"); break; 814 case 'I': txt = tr ("Peer is an incoming connection"); break; 815 case 'T': txt = tr ("Peer is connected over uTP"); break; 816 816 } 817 if ( !txt.isEmpty( ))818 codeTip += QString ("%1: %2\n").arg(ch).arg(txt);817 if (!txt.isEmpty ()) 818 codeTip += QString ("%1: %2\n").arg (ch).arg (txt); 819 819 } 820 820 821 if ( !codeTip.isEmpty())822 codeTip.resize ( codeTip.size()-1); // eat the trailing linefeed823 824 item->setText ( COL_UP, peer.rateToPeer.isZero() ? "" : Formatter::speedToString( peer.rateToPeer ));825 item->setText ( COL_DOWN, peer.rateToClient.isZero() ? "" : Formatter::speedToString( peer.rateToClient ));826 item->setText ( COL_PERCENT, peer.progress > 0 ? QString( "%1%" ).arg( (int)( peer.progress * 100.0 ) ) : "");827 item->setText ( COL_STATUS, code);828 item->setToolTip ( COL_STATUS, codeTip);829 830 peers2.insert ( key, item);831 } 832 } 833 myPeerTree->addTopLevelItems ( newItems);834 foreach ( QString key, myPeers.keys()) {835 if ( !peers2.contains( key )) { // old peer has disconnected836 QTreeWidgetItem * item = myPeers.value ( key, 0);837 myPeerTree->takeTopLevelItem ( myPeerTree->indexOfTopLevelItem( item ));821 if (!codeTip.isEmpty ()) 822 codeTip.resize (codeTip.size ()-1); // eat the trailing linefeed 823 824 item->setText (COL_UP, peer.rateToPeer.isZero () ? "" : Formatter::speedToString (peer.rateToPeer)); 825 item->setText (COL_DOWN, peer.rateToClient.isZero () ? "" : Formatter::speedToString (peer.rateToClient)); 826 item->setText (COL_PERCENT, peer.progress > 0 ? QString ("%1%").arg ( (int) (peer.progress * 100.0)) : ""); 827 item->setText (COL_STATUS, code); 828 item->setToolTip (COL_STATUS, codeTip); 829 830 peers2.insert (key, item); 831 } 832 } 833 myPeerTree->addTopLevelItems (newItems); 834 foreach (QString key, myPeers.keys ()) { 835 if (!peers2.contains (key)) { // old peer has disconnected 836 QTreeWidgetItem * item = myPeers.value (key, 0); 837 myPeerTree->takeTopLevelItem (myPeerTree->indexOfTopLevelItem (item)); 838 838 delete item; 839 839 } … … 841 841 myPeers = peers2; 842 842 843 if ( !single || myFilesDirty)844 myFileTreeView->clear ();845 if ( single)846 myFileTreeView->update ( torrents[0]->files( ) , myFilesDirty || myChangedTorrents);843 if (!single || myFilesDirty) 844 myFileTreeView->clear (); 845 if (single) 846 myFileTreeView->update (torrents[0]->files () , myFilesDirty || myChangedTorrents); 847 847 848 848 myFilesDirty = false; 849 849 myChangedTorrents = false; 850 850 myHavePendingRefresh = false; 851 foreach ( QWidget * w, myWidgets)852 w->setEnabled ( true);853 } 854 855 void 856 Details :: enableWhenChecked ( QCheckBox * box, QWidget * w)857 { 858 connect ( box, SIGNAL(toggled(bool)), w, SLOT(setEnabled(bool)));859 w->setEnabled ( box->isChecked( ));851 foreach (QWidget * w, myWidgets) 852 w->setEnabled (true); 853 } 854 855 void 856 Details :: enableWhenChecked (QCheckBox * box, QWidget * w) 857 { 858 connect (box, SIGNAL (toggled (bool)), w, SLOT (setEnabled (bool))); 859 w->setEnabled (box->isChecked ()); 860 860 } 861 861 … … 866 866 867 867 QWidget * 868 Details :: createInfoTab ()869 { 870 HIG * hig = new HIG ( this);871 872 hig->addSectionTitle ( tr( "Activity" ));873 hig->addRow ( tr( "Have:" ), myHaveLabel = new SqueezeLabel);874 hig->addRow ( tr( "Availability:" ), myAvailabilityLabel = new SqueezeLabel);875 hig->addRow ( tr( "Downloaded:" ), myDownloadedLabel = new SqueezeLabel);876 hig->addRow ( tr( "Uploaded:" ), myUploadedLabel = new SqueezeLabel);877 hig->addRow ( tr( "State:" ), myStateLabel = new SqueezeLabel);878 hig->addRow ( tr( "Running time:" ), myRunTimeLabel = new SqueezeLabel);879 hig->addRow ( tr( "Remaining time:" ), myETALabel = new SqueezeLabel);880 hig->addRow ( tr( "Last activity:" ), myLastActivityLabel = new SqueezeLabel);881 hig->addRow ( tr( "Error:" ), myErrorLabel = new SqueezeLabel);882 hig->addSectionDivider ();883 884 hig->addSectionDivider ();885 hig->addSectionTitle ( tr( "Details" ));886 hig->addRow ( tr( "Size:" ), mySizeLabel = new SqueezeLabel);887 hig->addRow ( tr( "Location:" ), myLocationLabel = new SqueezeLabel);888 hig->addRow ( tr( "Hash:" ), myHashLabel = new SqueezeLabel);889 hig->addRow ( tr( "Privacy:" ), myPrivacyLabel = new SqueezeLabel);890 hig->addRow ( tr( "Origin:" ), myOriginLabel = new SqueezeLabel);891 myOriginLabel->setMinimumWidth ( 325); // stop long origin strings from resizing the widgit892 hig->addRow ( tr( "Comment:" ), myCommentBrowser = new QTextBrowser);893 const int h = QFontMetrics (myCommentBrowser->font()).lineSpacing() * 4;894 myCommentBrowser->setFixedHeight ( h);895 896 hig->finish ();868 Details :: createInfoTab () 869 { 870 HIG * hig = new HIG (this); 871 872 hig->addSectionTitle (tr ("Activity")); 873 hig->addRow (tr ("Have:"), myHaveLabel = new SqueezeLabel); 874 hig->addRow (tr ("Availability:"), myAvailabilityLabel = new SqueezeLabel); 875 hig->addRow (tr ("Downloaded:"), myDownloadedLabel = new SqueezeLabel); 876 hig->addRow (tr ("Uploaded:"), myUploadedLabel = new SqueezeLabel); 877 hig->addRow (tr ("State:"), myStateLabel = new SqueezeLabel); 878 hig->addRow (tr ("Running time:"), myRunTimeLabel = new SqueezeLabel); 879 hig->addRow (tr ("Remaining time:"), myETALabel = new SqueezeLabel); 880 hig->addRow (tr ("Last activity:"), myLastActivityLabel = new SqueezeLabel); 881 hig->addRow (tr ("Error:"), myErrorLabel = new SqueezeLabel); 882 hig->addSectionDivider (); 883 884 hig->addSectionDivider (); 885 hig->addSectionTitle (tr ("Details")); 886 hig->addRow (tr ("Size:"), mySizeLabel = new SqueezeLabel); 887 hig->addRow (tr ("Location:"), myLocationLabel = new SqueezeLabel); 888 hig->addRow (tr ("Hash:"), myHashLabel = new SqueezeLabel); 889 hig->addRow (tr ("Privacy:"), myPrivacyLabel = new SqueezeLabel); 890 hig->addRow (tr ("Origin:"), myOriginLabel = new SqueezeLabel); 891 myOriginLabel->setMinimumWidth (325); // stop long origin strings from resizing the widgit 892 hig->addRow (tr ("Comment:"), myCommentBrowser = new QTextBrowser); 893 const int h = QFontMetrics (myCommentBrowser->font ()).lineSpacing () * 4; 894 myCommentBrowser->setFixedHeight (h); 895 896 hig->finish (); 897 897 898 898 return hig; … … 930 930 Details :: onSpinBoxEditingFinished () 931 931 { 932 const QObject * spin = sender ();933 const tr_quark key = spin->property (PREF_KEY).toInt();934 const QDoubleSpinBox * d = qobject_cast<const QDoubleSpinBox*> ( spin);932 const QObject * spin = sender (); 933 const tr_quark key = spin->property (PREF_KEY).toInt (); 934 const QDoubleSpinBox * d = qobject_cast<const QDoubleSpinBox*> (spin); 935 935 if (d) 936 mySession.torrentSet ( myIds, key, d->value( ));936 mySession.torrentSet (myIds, key, d->value ()); 937 937 else 938 mySession.torrentSet ( myIds, key, qobject_cast<const QSpinBox*>(spin)->value( ));939 getNewData ();938 mySession.torrentSet (myIds, key, qobject_cast<const QSpinBox*> (spin)->value ()); 939 getNewData (); 940 940 } 941 941 … … 950 950 Details :: onIdleModeChanged (int index) 951 951 { 952 const int val = myIdleCombo->itemData (index).toInt();952 const int val = myIdleCombo->itemData (index).toInt (); 953 953 mySession.torrentSet (myIds, TR_KEY_seedIdleMode, val); 954 954 getNewData (); … … 958 958 Details :: onRatioModeChanged (int index) 959 959 { 960 const int val = myRatioCombo->itemData (index).toInt();960 const int val = myRatioCombo->itemData (index).toInt (); 961 961 mySession.torrentSet (myIds, TR_KEY_seedRatioMode, val); 962 962 } … … 965 965 Details :: onBandwidthPriorityChanged (int index) 966 966 { 967 if ( index != -1)968 { 969 const int priority = myBandwidthPriorityCombo->itemData (index).toInt();970 mySession.torrentSet ( myIds, TR_KEY_bandwidthPriority, priority);971 getNewData ();967 if (index != -1) 968 { 969 const int priority = myBandwidthPriorityCombo->itemData (index).toInt (); 970 mySession.torrentSet (myIds, TR_KEY_bandwidthPriority, priority); 971 getNewData (); 972 972 } 973 973 } … … 976 976 Details :: onTrackerSelectionChanged () 977 977 { 978 const int selectionCount = myTrackerView->selectionModel ()->selectedRows().size();978 const int selectionCount = myTrackerView->selectionModel ()->selectedRows ().size (); 979 979 myEditTrackerButton->setEnabled (selectionCount == 1); 980 980 myRemoveTrackerButton->setEnabled (selectionCount > 0); … … 986 986 bool ok = false; 987 987 const QString url = QInputDialog::getText (this, 988 tr ("Add URL "),989 tr ("Add tracker announce URL:"),990 QLineEdit::Normal, QString (), &ok);991 if (!ok)988 tr ("Add URL "), 989 tr ("Add tracker announce URL:"), 990 QLineEdit::Normal, QString (), &ok); 991 if (!ok) 992 992 { 993 993 // user pressed "cancel" -- noop 994 994 } 995 else if (!QUrl (url).isValid())996 { 997 QMessageBox::warning ( this, tr("Error"), tr("Invalid URL \"%1\"").arg(url));995 else if (!QUrl (url).isValid ()) 996 { 997 QMessageBox::warning (this, tr ("Error"), tr ("Invalid URL \"%1\"").arg (url)); 998 998 } 999 999 else … … 1002 1002 1003 1003 foreach (int id, myIds) 1004 if (myTrackerModel->find (id,url) == -1)1004 if (myTrackerModel->find (id,url) == -1) 1005 1005 ids.insert (id); 1006 1006 1007 if (ids.empty ()) // all the torrents already have this tracker1007 if (ids.empty ()) // all the torrents already have this tracker 1008 1008 { 1009 QMessageBox::warning (this, tr ("Error"), tr("Tracker already exists."));1009 QMessageBox::warning (this, tr ("Error"), tr ("Tracker already exists.")); 1010 1010 } 1011 1011 else … … 1022 1022 Details :: onEditTrackerClicked () 1023 1023 { 1024 QItemSelectionModel * selectionModel = myTrackerView->selectionModel ();1025 QModelIndexList selectedRows = selectionModel->selectedRows ();1026 assert (selectedRows.size () == 1);1027 QModelIndex i = selectionModel->currentIndex ();1028 const TrackerInfo trackerInfo = myTrackerView->model ()->data(i, TrackerModel::TrackerRole).value<TrackerInfo>();1024 QItemSelectionModel * selectionModel = myTrackerView->selectionModel (); 1025 QModelIndexList selectedRows = selectionModel->selectedRows (); 1026 assert (selectedRows.size () == 1); 1027 QModelIndex i = selectionModel->currentIndex (); 1028 const TrackerInfo trackerInfo = myTrackerView->model ()->data (i, TrackerModel::TrackerRole).value<TrackerInfo> (); 1029 1029 1030 1030 bool ok = false; 1031 1031 const QString newval = QInputDialog::getText (this, 1032 tr ("Edit URL "),1033 tr ("Edit tracker announce URL:"),1032 tr ("Edit URL "), 1033 tr ("Edit tracker announce URL:"), 1034 1034 QLineEdit::Normal, 1035 1035 trackerInfo.st.announce, &ok); … … 1039 1039 // user pressed "cancel" -- noop 1040 1040 } 1041 else if ( !QUrl(newval).isValid( ))1042 { 1043 QMessageBox::warning (this, tr ("Error"), tr("Invalid URL \"%1\"").arg(newval));1041 else if (!QUrl (newval).isValid ()) 1042 { 1043 QMessageBox::warning (this, tr ("Error"), tr ("Invalid URL \"%1\"").arg (newval)); 1044 1044 } 1045 1045 else … … 1056 1056 1057 1057 void 1058 Details :: onRemoveTrackerClicked ()1058 Details :: onRemoveTrackerClicked () 1059 1059 { 1060 1060 // make a map of torrentIds to announce URLs to remove 1061 QItemSelectionModel * selectionModel = myTrackerView->selectionModel ();1062 QModelIndexList selectedRows = selectionModel->selectedRows ();1061 QItemSelectionModel * selectionModel = myTrackerView->selectionModel (); 1062 QModelIndexList selectedRows = selectionModel->selectedRows (); 1063 1063 QMap<int,int> torrentId_to_trackerIds; 1064 foreach ( QModelIndex i, selectedRows)1065 { 1066 const TrackerInfo inf = myTrackerView->model ()->data( i, TrackerModel::TrackerRole ).value<TrackerInfo>();1067 torrentId_to_trackerIds.insertMulti ( inf.torrentId, inf.st.id);1064 foreach (QModelIndex i, selectedRows) 1065 { 1066 const TrackerInfo inf = myTrackerView->model ()->data (i, TrackerModel::TrackerRole).value<TrackerInfo> (); 1067 torrentId_to_trackerIds.insertMulti (inf.torrentId, inf.st.id); 1068 1068 } 1069 1069 1070 1070 // batch all of a tracker's torrents into one command 1071 foreach ( int id, torrentId_to_trackerIds.uniqueKeys( ))1071 foreach (int id, torrentId_to_trackerIds.uniqueKeys ()) 1072 1072 { 1073 1073 QSet<int> ids; 1074 1074 ids << id; 1075 mySession.torrentSet ( ids, TR_KEY_trackerRemove, torrentId_to_trackerIds.values( id ));1076 } 1077 1078 selectionModel->clearSelection ();1079 getNewData ();1075 mySession.torrentSet (ids, TR_KEY_trackerRemove, torrentId_to_trackerIds.values (id)); 1076 } 1077 1078 selectionModel->clearSelection (); 1079 getNewData (); 1080 1080 } 1081 1081 1082 1082 QWidget * 1083 Details :: createOptionsTab ()1083 Details :: createOptionsTab () 1084 1084 { 1085 1085 QSpinBox * s; … … 1088 1088 QHBoxLayout * h; 1089 1089 QDoubleSpinBox * ds; 1090 const QString speed_K_str = Formatter::unitStr ( Formatter::SPEED, Formatter::KB);1091 1092 HIG * hig = new HIG ( this);1093 hig->addSectionTitle ( tr( "Speed" ));1094 1095 c = new QCheckBox ( tr( "Honor global &limits" ));1090 const QString speed_K_str = Formatter::unitStr (Formatter::SPEED, Formatter::KB); 1091 1092 HIG * hig = new HIG (this); 1093 hig->addSectionTitle (tr ("Speed")); 1094 1095 c = new QCheckBox (tr ("Honor global &limits")); 1096 1096 mySessionLimitCheck = c; 1097 hig->addWideControl ( c);1098 connect ( c, SIGNAL(clicked(bool)), this, SLOT(onHonorsSessionLimitsToggled(bool)));1099 1100 c = new QCheckBox ( tr( "Limit &download speed (%1):" ).arg( speed_K_str ));1097 hig->addWideControl (c); 1098 connect (c, SIGNAL (clicked (bool)), this, SLOT (onHonorsSessionLimitsToggled (bool))); 1099 1100 c = new QCheckBox (tr ("Limit &download speed (%1):").arg (speed_K_str)); 1101 1101 mySingleDownCheck = c; 1102 s = new QSpinBox ();1102 s = new QSpinBox (); 1103 1103 s->setProperty (PREF_KEY, TR_KEY_downloadLimit); 1104 s->setSingleStep ( 5);1105 s->setRange ( 0, INT_MAX);1104 s->setSingleStep (5); 1105 s->setRange (0, INT_MAX); 1106 1106 mySingleDownSpin = s; 1107 hig->addRow ( c, s);1108 enableWhenChecked ( c, s);1109 connect ( c, SIGNAL(clicked(bool)), this, SLOT(onDownloadLimitedToggled(bool)));1110 connect ( s, SIGNAL(editingFinished()), this, SLOT(onSpinBoxEditingFinished()));1111 1112 c = new QCheckBox ( tr( "Limit &upload speed (%1):" ).arg( speed_K_str ));1107 hig->addRow (c, s); 1108 enableWhenChecked (c, s); 1109 connect (c, SIGNAL (clicked (bool)), this, SLOT (onDownloadLimitedToggled (bool))); 1110 connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ())); 1111 1112 c = new QCheckBox (tr ("Limit &upload speed (%1):").arg (speed_K_str)); 1113 1113 mySingleUpCheck = c; 1114 s = new QSpinBox ();1115 s->setSingleStep ( 5);1116 s->setRange ( 0, INT_MAX);1117 s->setProperty ( PREF_KEY, TR_KEY_uploadLimit);1114 s = new QSpinBox (); 1115 s->setSingleStep (5); 1116 s->setRange (0, INT_MAX); 1117 s->setProperty (PREF_KEY, TR_KEY_uploadLimit); 1118 1118 mySingleUpSpin = s; 1119 hig->addRow ( c, s);1120 enableWhenChecked ( c, s);1121 connect ( c, SIGNAL(clicked(bool)), this, SLOT(onUploadLimitedToggled(bool)));1122 connect ( s, SIGNAL(editingFinished()), this, SLOT(onSpinBoxEditingFinished()));1119 hig->addRow (c, s); 1120 enableWhenChecked (c, s); 1121 connect (c, SIGNAL (clicked (bool)), this, SLOT (onUploadLimitedToggled (bool))); 1122 connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ())); 1123 1123 1124 1124 m = new QComboBox; 1125 m->addItem ( tr( "High" ), TR_PRI_HIGH);1126 m->addItem ( tr( "Normal" ), TR_PRI_NORMAL);1127 m->addItem ( tr( "Low" ), TR_PRI_LOW);1128 connect ( m, SIGNAL(currentIndexChanged(int)), this, SLOT(onBandwidthPriorityChanged(int)));1129 hig->addRow ( tr( "Torrent &priority:" ), m);1125 m->addItem (tr ("High"), TR_PRI_HIGH); 1126 m->addItem (tr ("Normal"), TR_PRI_NORMAL); 1127 m->addItem (tr ("Low"), TR_PRI_LOW); 1128 connect (m, SIGNAL (currentIndexChanged (int)), this, SLOT (onBandwidthPriorityChanged (int))); 1129 hig->addRow (tr ("Torrent &priority:"), m); 1130 1130 myBandwidthPriorityCombo = m; 1131 1131 1132 hig->addSectionDivider ();1133 hig->addSectionTitle ( tr( "Seeding Limits" ));1134 1135 h = new QHBoxLayout ();1136 h->setSpacing ( HIG :: PAD);1132 hig->addSectionDivider (); 1133 hig->addSectionTitle (tr ("Seeding Limits")); 1134 1135 h = new QHBoxLayout (); 1136 h->setSpacing (HIG :: PAD); 1137 1137 m = new QComboBox; 1138 m->addItem ( tr( "Use Global Settings" ), TR_RATIOLIMIT_GLOBAL);1139 m->addItem ( tr( "Seed regardless of ratio" ), TR_RATIOLIMIT_UNLIMITED);1140 m->addItem ( tr( "Stop seeding at ratio:" ), TR_RATIOLIMIT_SINGLE);1141 connect ( m, SIGNAL(currentIndexChanged(int)), this, SLOT(onRatioModeChanged(int)));1142 h->addWidget ( myRatioCombo = m);1143 ds = new QDoubleSpinBox ();1144 ds->setRange ( 0.5, INT_MAX);1145 ds->setProperty ( PREF_KEY, TR_KEY_seedRatioLimit);1146 connect ( ds, SIGNAL(editingFinished()), this, SLOT(onSpinBoxEditingFinished()));1147 h->addWidget ( myRatioSpin = ds);1148 hig->addRow ( tr( "&Ratio:" ), h, m);1149 1150 h = new QHBoxLayout ();1151 h->setSpacing ( HIG :: PAD);1138 m->addItem (tr ("Use Global Settings"), TR_RATIOLIMIT_GLOBAL); 1139 m->addItem (tr ("Seed regardless of ratio"), TR_RATIOLIMIT_UNLIMITED); 1140 m->addItem (tr ("Stop seeding at ratio:"), TR_RATIOLIMIT_SINGLE); 1141 connect (m, SIGNAL (currentIndexChanged (int)), this, SLOT (onRatioModeChanged (int))); 1142 h->addWidget (myRatioCombo = m); 1143 ds = new QDoubleSpinBox (); 1144 ds->setRange (0.5, INT_MAX); 1145 ds->setProperty (PREF_KEY, TR_KEY_seedRatioLimit); 1146 connect (ds, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ())); 1147 h->addWidget (myRatioSpin = ds); 1148 hig->addRow (tr ("&Ratio:"), h, m); 1149 1150 h = new QHBoxLayout (); 1151 h->setSpacing (HIG :: PAD); 1152 1152 m = new QComboBox; 1153 m->addItem ( tr( "Use Global Settings" ), TR_IDLELIMIT_GLOBAL);1154 m->addItem ( tr( "Seed regardless of activity" ), TR_IDLELIMIT_UNLIMITED);1155 m->addItem ( tr( "Stop seeding if idle for N minutes:" ), TR_IDLELIMIT_SINGLE);1156 connect ( m, SIGNAL(currentIndexChanged(int)), this, SLOT(onIdleModeChanged(int)));1157 h->addWidget ( myIdleCombo = m);1158 s = new QSpinBox ();1159 s->setSingleStep ( 5);1160 s->setRange ( 1, 9999);1161 s->setProperty ( PREF_KEY, TR_KEY_seedIdleLimit);1162 connect ( s, SIGNAL(editingFinished()), this, SLOT(onSpinBoxEditingFinished()));1163 h->addWidget ( myIdleSpin = s);1164 hig->addRow ( tr( "&Idle:" ), h, m);1165 1166 1167 hig->addSectionDivider ();1168 hig->addSectionTitle ( tr( "Peer Connections" ));1169 1170 s = new QSpinBox ();1171 s->setSingleStep ( 5);1172 s->setRange ( 1, 300);1173 s->setProperty ( PREF_KEY, TR_KEY_peer_limit);1174 connect ( s, SIGNAL(editingFinished()), this, SLOT(onSpinBoxEditingFinished()));1153 m->addItem (tr ("Use Global Settings"), TR_IDLELIMIT_GLOBAL); 1154 m->addItem (tr ("Seed regardless of activity"), TR_IDLELIMIT_UNLIMITED); 1155 m->addItem (tr ("Stop seeding if idle for N minutes:"), TR_IDLELIMIT_SINGLE); 1156 connect (m, SIGNAL (currentIndexChanged (int)), this, SLOT (onIdleModeChanged (int))); 1157 h->addWidget (myIdleCombo = m); 1158 s = new QSpinBox (); 1159 s->setSingleStep (5); 1160 s->setRange (1, 9999); 1161 s->setProperty (PREF_KEY, TR_KEY_seedIdleLimit); 1162 connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ())); 1163 h->addWidget (myIdleSpin = s); 1164 hig->addRow (tr ("&Idle:"), h, m); 1165 1166 1167 hig->addSectionDivider (); 1168 hig->addSectionTitle (tr ("Peer Connections")); 1169 1170 s = new QSpinBox (); 1171 s->setSingleStep (5); 1172 s->setRange (1, 300); 1173 s->setProperty (PREF_KEY, TR_KEY_peer_limit); 1174 connect (s, SIGNAL (editingFinished ()), this, SLOT (onSpinBoxEditingFinished ())); 1175 1175 myPeerLimitSpin = s; 1176 hig->addRow ( tr( "&Maximum peers:" ), s);1177 1178 hig->finish ();1176 hig->addRow (tr ("&Maximum peers:"), s); 1177 1178 hig->finish (); 1179 1179 1180 1180 return hig; … … 1186 1186 1187 1187 QWidget * 1188 Details :: createTrackerTab ()1188 Details :: createTrackerTab () 1189 1189 { 1190 1190 QCheckBox * c; 1191 1191 QPushButton * p; 1192 1192 QWidget * top = new QWidget; 1193 QVBoxLayout * v = new QVBoxLayout ( top);1194 QHBoxLayout * h = new QHBoxLayout ();1195 QVBoxLayout * v2 = new QVBoxLayout ();1196 1197 v->setSpacing ( HIG::PAD_BIG);1198 v->setContentsMargins ( HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG);1199 1200 h->setSpacing ( HIG::PAD);1201 h->setContentsMargins ( HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL);1202 1203 v2->setSpacing ( HIG::PAD);1193 QVBoxLayout * v = new QVBoxLayout (top); 1194 QHBoxLayout * h = new QHBoxLayout (); 1195 QVBoxLayout * v2 = new QVBoxLayout (); 1196 1197 v->setSpacing (HIG::PAD_BIG); 1198 v->setContentsMargins (HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG); 1199 1200 h->setSpacing (HIG::PAD); 1201 h->setContentsMargins (HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL); 1202 1203 v2->setSpacing (HIG::PAD); 1204 1204 1205 1205 myTrackerModel = new TrackerModel; 1206 1206 myTrackerFilter = new TrackerModelFilter; 1207 myTrackerFilter->setSourceModel ( myTrackerModel);1207 myTrackerFilter->setSourceModel (myTrackerModel); 1208 1208 myTrackerView = new QTreeView; 1209 myTrackerView->setModel ( myTrackerFilter);1210 myTrackerView->setHeaderHidden ( true);1211 myTrackerView->setSelectionMode ( QTreeWidget::ExtendedSelection);1212 myTrackerView->setRootIsDecorated ( false);1213 myTrackerView->setIndentation ( 2);1214 myTrackerView->setItemsExpandable ( false);1215 myTrackerView->setAlternatingRowColors ( true);1216 myTrackerView->setItemDelegate ( myTrackerDelegate = new TrackerDelegate( ));1217 connect ( myTrackerView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(onTrackerSelectionChanged()));1218 h->addWidget ( myTrackerView, 1);1219 1220 p = new QPushButton ();1221 p->setIcon ( getStockIcon( "list-add", QStyle::SP_DialogOpenButton ));1222 p->setToolTip ( tr( "Add Tracker"));1209 myTrackerView->setModel (myTrackerFilter); 1210 myTrackerView->setHeaderHidden (true); 1211 myTrackerView->setSelectionMode (QTreeWidget::ExtendedSelection); 1212 myTrackerView->setRootIsDecorated (false); 1213 myTrackerView->setIndentation (2); 1214 myTrackerView->setItemsExpandable (false); 1215 myTrackerView->setAlternatingRowColors (true); 1216 myTrackerView->setItemDelegate (myTrackerDelegate = new TrackerDelegate ()); 1217 connect (myTrackerView->selectionModel (), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT (onTrackerSelectionChanged ())); 1218 h->addWidget (myTrackerView, 1); 1219 1220 p = new QPushButton (); 1221 p->setIcon (getStockIcon ("list-add", QStyle::SP_DialogOpenButton)); 1222 p->setToolTip (tr ("Add Tracker")); 1223 1223 myAddTrackerButton = p; 1224 v2->addWidget ( p, 1);1225 connect ( p, SIGNAL(clicked(bool)), this, SLOT(onAddTrackerClicked()));1226 1227 p = new QPushButton ();1228 p->setIcon ( getStockIcon( "document-properties", QStyle::SP_DesktopIcon ));1229 p->setToolTip ( tr( "Edit Tracker"));1224 v2->addWidget (p, 1); 1225 connect (p, SIGNAL (clicked (bool)), this, SLOT (onAddTrackerClicked ())); 1226 1227 p = new QPushButton (); 1228 p->setIcon (getStockIcon ("document-properties", QStyle::SP_DesktopIcon)); 1229 p->setToolTip (tr ("Edit Tracker")); 1230 1230 myAddTrackerButton = p; 1231 p->setEnabled ( false);1231 p->setEnabled (false); 1232 1232 myEditTrackerButton = p; 1233 v2->addWidget ( p, 1);1234 connect ( p, SIGNAL(clicked(bool)), this, SLOT(onEditTrackerClicked()));1235 1236 p = new QPushButton ();1237 p->setIcon ( getStockIcon( "list-remove", QStyle::SP_TrashIcon ));1238 p->setToolTip ( tr( "Remove Trackers"));1239 p->setEnabled ( false);1233 v2->addWidget (p, 1); 1234 connect (p, SIGNAL (clicked (bool)), this, SLOT (onEditTrackerClicked ())); 1235 1236 p = new QPushButton (); 1237 p->setIcon (getStockIcon ("list-remove", QStyle::SP_TrashIcon)); 1238 p->setToolTip (tr ("Remove Trackers")); 1239 p->setEnabled (false); 1240 1240 myRemoveTrackerButton = p; 1241 v2->addWidget ( p, 1);1242 connect ( p, SIGNAL(clicked(bool)), this, SLOT(onRemoveTrackerClicked()));1243 1244 v2->addStretch ( 1);1245 1246 h->addLayout ( v2, 1);1247 h->setStretch ( 1, 0);1248 1249 v->addLayout ( h, 1);1250 1251 c = new QCheckBox ( tr( "Show &more details" ));1252 c->setChecked ( myPrefs.getBool( Prefs::SHOW_TRACKER_SCRAPES ));1241 v2->addWidget (p, 1); 1242 connect (p, SIGNAL (clicked (bool)), this, SLOT (onRemoveTrackerClicked ())); 1243 1244 v2->addStretch (1); 1245 1246 h->addLayout (v2, 1); 1247 h->setStretch (1, 0); 1248 1249 v->addLayout (h, 1); 1250 1251 c = new QCheckBox (tr ("Show &more details")); 1252 c->setChecked (myPrefs.getBool (Prefs::SHOW_TRACKER_SCRAPES)); 1253 1253 myShowTrackerScrapesCheck = c; 1254 v->addWidget ( c, 1);1255 connect ( c, SIGNAL(clicked(bool)), this, SLOT(onShowTrackerScrapesToggled(bool)));1256 1257 c = new QCheckBox ( tr( "Show &backup trackers" ));1258 c->setChecked ( myPrefs.getBool( Prefs::SHOW_BACKUP_TRACKERS ));1254 v->addWidget (c, 1); 1255 connect (c, SIGNAL (clicked (bool)), this, SLOT (onShowTrackerScrapesToggled (bool))); 1256 1257 c = new QCheckBox (tr ("Show &backup trackers")); 1258 c->setChecked (myPrefs.getBool (Prefs::SHOW_BACKUP_TRACKERS)); 1259 1259 myShowBackupTrackersCheck = c; 1260 v->addWidget ( c, 1);1261 connect ( c, SIGNAL(clicked(bool)), this, SLOT(onShowBackupTrackersToggled(bool)));1260 v->addWidget (c, 1); 1261 connect (c, SIGNAL (clicked (bool)), this, SLOT (onShowBackupTrackersToggled (bool))); 1262 1262 1263 1263 return top; … … 1269 1269 1270 1270 QWidget * 1271 Details :: createPeersTab ()1271 Details :: createPeersTab () 1272 1272 { 1273 1273 QWidget * top = new QWidget; 1274 QVBoxLayout * v = new QVBoxLayout ( top);1275 v->setSpacing ( HIG :: PAD_BIG);1276 v->setContentsMargins ( HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG);1274 QVBoxLayout * v = new QVBoxLayout (top); 1275 v->setSpacing (HIG :: PAD_BIG); 1276 v->setContentsMargins (HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG, HIG::PAD_BIG); 1277 1277 1278 1278 QStringList headers; 1279 headers << QString () << tr("Up") << tr("Down") << tr("%") << tr("Status") << tr("Address") << tr("Client");1279 headers << QString () << tr ("Up") << tr ("Down") << tr ("%") << tr ("Status") << tr ("Address") << tr ("Client"); 1280 1280 myPeerTree = new QTreeWidget; 1281 myPeerTree->setUniformRowHeights ( true);1282 myPeerTree->setHeaderLabels ( headers);1283 myPeerTree->setColumnWidth ( 0, 20);1284 myPeerTree->setSortingEnabled ( true);1285 myPeerTree->sortByColumn ( COL_ADDRESS, Qt::AscendingOrder);1286 myPeerTree->setRootIsDecorated ( false);1287 myPeerTree->setTextElideMode ( Qt::ElideRight);1288 v->addWidget ( myPeerTree, 1);1289 1290 const QFontMetrics m ( font( ));1291 QSize size = m.size ( 0, "1024 MiB/s");1292 myPeerTree->setColumnWidth ( COL_UP, size.width( ));1293 myPeerTree->setColumnWidth ( COL_DOWN, size.width( ));1294 size = m.size ( 0, " 100% ");1295 myPeerTree->setColumnWidth ( COL_PERCENT, size.width( ));1296 size = m.size ( 0, "ODUK?EXI");1297 myPeerTree->setColumnWidth ( COL_STATUS, size.width( ));1298 size = m.size ( 0, "888.888.888.888");1299 myPeerTree->setColumnWidth ( COL_ADDRESS, size.width( ));1300 size = m.size ( 0, "Some BitTorrent Client");1301 myPeerTree->setColumnWidth ( COL_CLIENT, size.width( ));1302 myPeerTree->setAlternatingRowColors ( true);1281 myPeerTree->setUniformRowHeights (true); 1282 myPeerTree->setHeaderLabels (headers); 1283 myPeerTree->setColumnWidth (0, 20); 1284 myPeerTree->setSortingEnabled (true); 1285 myPeerTree->sortByColumn (COL_ADDRESS, Qt::AscendingOrder); 1286 myPeerTree->setRootIsDecorated (false); 1287 myPeerTree->setTextElideMode (Qt::ElideRight); 1288 v->addWidget (myPeerTree, 1); 1289 1290 const QFontMetrics m (font ()); 1291 QSize size = m.size (0, "1024 MiB/s"); 1292 myPeerTree->setColumnWidth (COL_UP, size.width ()); 1293 myPeerTree->setColumnWidth (COL_DOWN, size.width ()); 1294 size = m.size (0, " 100% "); 1295 myPeerTree->setColumnWidth (COL_PERCENT, size.width ()); 1296 size = m.size (0, "ODUK?EXI"); 1297 myPeerTree->setColumnWidth (COL_STATUS, size.width ()); 1298 size = m.size (0, "888.888.888.888"); 1299 myPeerTree->setColumnWidth (COL_ADDRESS, size.width ()); 1300 size = m.size (0, "Some BitTorrent Client"); 1301 myPeerTree->setColumnWidth (COL_CLIENT, size.width ()); 1302 myPeerTree->setAlternatingRowColors (true); 1303 1303 1304 1304 return top; … … 1310 1310 1311 1311 QWidget * 1312 Details :: createFilesTab ()1313 { 1314 myFileTreeView = new FileTreeView ();1315 1316 connect ( myFileTreeView, SIGNAL( priorityChanged(const QSet<int>&, int)),1317 this, SLOT ( onFilePriorityChanged(const QSet<int>&, int)));1318 1319 connect ( myFileTreeView, SIGNAL( wantedChanged(const QSet<int>&, bool)),1320 this, SLOT ( onFileWantedChanged(const QSet<int>&, bool)));1321 1322 connect ( myFileTreeView, SIGNAL( pathEdited(const QString&, const QString&)),1323 this, SLOT (onPathEdited (const QString&, const QString&)));1312 Details :: createFilesTab () 1313 { 1314 myFileTreeView = new FileTreeView (); 1315 1316 connect (myFileTreeView, SIGNAL ( priorityChanged (const QSet<int>&, int)), 1317 this, SLOT ( onFilePriorityChanged (const QSet<int>&, int))); 1318 1319 connect (myFileTreeView, SIGNAL ( wantedChanged (const QSet<int>&, bool)), 1320 this, SLOT ( onFileWantedChanged (const QSet<int>&, bool))); 1321 1322 connect (myFileTreeView, SIGNAL (pathEdited (const QString&, const QString&)), 1323 this, SLOT (onPathEdited (const QString&, const QString&))); 1324 1324 1325 1325 return myFileTreeView; … … 1346 1346 } 1347 1347 1348 mySession.torrentSet (myIds, key, indices.toList ());1349 getNewData ();1348 mySession.torrentSet (myIds, key, indices.toList ()); 1349 getNewData (); 1350 1350 } 1351 1351 … … 1354 1354 { 1355 1355 const tr_quark key = wanted ? TR_KEY_files_wanted : TR_KEY_files_unwanted; 1356 mySession.torrentSet (myIds, key, indices.toList ());1356 mySession.torrentSet (myIds, key, indices.toList ()); 1357 1357 getNewData (); 1358 1358 } -
trunk/qt/details.h
r13810 r13869 43 43 class Details: public QDialog 44 44 { 45 45 Q_OBJECT 46 46 47 48 void getNewData();47 private: 48 void getNewData (); 49 49 50 51 void onTorrentChanged();52 void onTorrentFileListRebuilt();53 void onTimer();50 private slots: 51 void onTorrentChanged (); 52 void onTorrentFileListRebuilt (); 53 void onTimer (); 54 54 55 56 Details( Session&, Prefs&, TorrentModel&, QWidget * parent = 0);57 ~Details();58 void setIds( const QSet<int>& ids);55 public: 56 Details (Session&, Prefs&, TorrentModel&, QWidget * parent = 0); 57 ~Details (); 58 void setIds (const QSet<int>& ids); 59 59 60 61 QWidget * createPeersTab();62 QWidget * createTrackerTab();63 QWidget * createInfoTab();64 QWidget * createFilesTab();65 QWidget * createOptionsTab();60 private: 61 QWidget * createPeersTab (); 62 QWidget * createTrackerTab (); 63 QWidget * createInfoTab (); 64 QWidget * createFilesTab (); 65 QWidget * createOptionsTab (); 66 66 67 68 QIcon getStockIcon( const QString& freedesktop_name, int fallback);69 QString timeToStringRounded( int seconds);70 QString trimToDesiredWidth( const QString& str);71 void enableWhenChecked( QCheckBox *, QWidget *);67 private: 68 QIcon getStockIcon (const QString& freedesktop_name, int fallback); 69 QString timeToStringRounded (int seconds); 70 QString trimToDesiredWidth (const QString& str); 71 void enableWhenChecked (QCheckBox *, QWidget *); 72 72 73 74 75 76 77 78 79 80 73 private: 74 Session& mySession; 75 Prefs& myPrefs; 76 TorrentModel& myModel; 77 QSet<int> myIds; 78 QTimer myTimer; 79 bool myChangedTorrents; 80 bool myHavePendingRefresh; 81 81 82 83 84 85 86 87 88 89 90 82 QLabel * myStateLabel; 83 QLabel * myHaveLabel; 84 QLabel * myAvailabilityLabel; 85 QLabel * myDownloadedLabel; 86 QLabel * myUploadedLabel; 87 QLabel * myErrorLabel; 88 QLabel * myRunTimeLabel; 89 QLabel * myETALabel; 90 QLabel * myLastActivityLabel; 91 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 92 QCheckBox * mySessionLimitCheck; 93 QCheckBox * mySingleDownCheck; 94 QCheckBox * mySingleUpCheck; 95 QCheckBox * myShowTrackerScrapesCheck; 96 QCheckBox * myShowBackupTrackersCheck; 97 QPushButton * myAddTrackerButton; 98 QPushButton * myEditTrackerButton; 99 QPushButton * myRemoveTrackerButton; 100 QSpinBox * mySingleDownSpin; 101 QSpinBox * mySingleUpSpin; 102 QComboBox * myRatioCombo; 103 QDoubleSpinBox * myRatioSpin; 104 QComboBox * myIdleCombo; 105 QSpinBox * myIdleSpin; 106 QSpinBox * myPeerLimitSpin; 107 QComboBox * myBandwidthPriorityCombo; 108 108 109 110 111 112 113 114 109 QLabel * mySizeLabel; 110 QLabel * myHashLabel; 111 QLabel * myPrivacyLabel; 112 QLabel * myOriginLabel; 113 QLabel * myLocationLabel; 114 QTextBrowser * myCommentBrowser; 115 115 116 117 118 119 120 121 122 123 116 QLabel * myTrackerLabel; 117 QLabel * myScrapeTimePrevLabel; 118 QLabel * myScrapeTimeNextLabel; 119 QLabel * myScrapeResponseLabel; 120 QLabel * myAnnounceTimePrevLabel; 121 QLabel * myAnnounceTimeNextLabel; 122 QLabel * myAnnounceResponseLabel; 123 QLabel * myAnnounceManualLabel; 124 124 125 126 127 128 129 130 125 TrackerModel * myTrackerModel; 126 TrackerModelFilter * myTrackerFilter; 127 TrackerDelegate * myTrackerDelegate; 128 QTreeView * myTrackerView; 129 //QMap<QString,QTreeWidgetItem*> myTrackerTiers; 130 //QMap<QString,QTreeWidgetItem*> myTrackerItems; 131 131 132 133 132 QTreeWidget * myPeerTree; 133 QMap<QString,QTreeWidgetItem*> myPeers; 134 134 135 135 QWidgetList myWidgets; 136 136 137 137 FileTreeView * myFileTreeView; 138 138 139 139 bool myFilesDirty; 140 140 141 142 void refreshPref( int key);143 void onBandwidthPriorityChanged( int);144 void onFilePriorityChanged( const QSet<int>& fileIndices, int);145 void onFileWantedChanged( const QSet<int>& fileIndices, bool);146 147 void onHonorsSessionLimitsToggled( bool);148 void onDownloadLimitedToggled( bool);149 void onSpinBoxEditingFinished();150 void onUploadLimitedToggled( bool);151 void onRatioModeChanged( int);152 void onIdleModeChanged( int);153 void onShowTrackerScrapesToggled( bool);154 void onShowBackupTrackersToggled( bool);155 void onTrackerSelectionChanged();156 void onAddTrackerClicked();157 void onEditTrackerClicked();158 void onRemoveTrackerClicked();159 void refresh();141 private slots: 142 void refreshPref (int key); 143 void onBandwidthPriorityChanged (int); 144 void onFilePriorityChanged (const QSet<int>& fileIndices, int); 145 void onFileWantedChanged (const QSet<int>& fileIndices, bool); 146 void onPathEdited (const QString& oldpath, const QString& newname); 147 void onHonorsSessionLimitsToggled (bool); 148 void onDownloadLimitedToggled (bool); 149 void onSpinBoxEditingFinished (); 150 void onUploadLimitedToggled (bool); 151 void onRatioModeChanged (int); 152 void onIdleModeChanged (int); 153 void onShowTrackerScrapesToggled (bool); 154 void onShowBackupTrackersToggled (bool); 155 void onTrackerSelectionChanged (); 156 void onAddTrackerClicked (); 157 void onEditTrackerClicked (); 158 void onRemoveTrackerClicked (); 159 void refresh (); 160 160 }; 161 161 -
trunk/qt/filterbar.cc
r13720 r13869 39 39 namespace 40 40 { 41 int getHSpacing( QWidget * w)42 43 return qMax( int(HIG::PAD_SMALL), w->style()->pixelMetric( QStyle::PM_LayoutHorizontalSpacing, 0, w ));44 45 } 46 47 FilterBarComboBoxDelegate :: FilterBarComboBoxDelegate ( QObject * parent, QComboBox * combo):48 QItemDelegate( parent),49 myCombo( combo)41 int getHSpacing (QWidget * w) 42 { 43 return qMax (int (HIG::PAD_SMALL), w->style ()->pixelMetric (QStyle::PM_LayoutHorizontalSpacing, 0, w)); 44 } 45 } 46 47 FilterBarComboBoxDelegate :: FilterBarComboBoxDelegate (QObject * parent, QComboBox * combo): 48 QItemDelegate (parent), 49 myCombo (combo) 50 50 { 51 51 } 52 52 53 53 bool 54 FilterBarComboBoxDelegate :: isSeparator ( const QModelIndex &index)55 { 56 return index.data(Qt::AccessibleDescriptionRole).toString() == QLatin1String("separator");57 } 58 void 59 FilterBarComboBoxDelegate :: setSeparator ( QAbstractItemModel * model, const QModelIndex& index)60 { 61 model->setData( index, QString::fromLatin1("separator"), Qt::AccessibleDescriptionRole);62 63 if( QStandardItemModel *m = qobject_cast<QStandardItemModel*>(model))64 if (QStandardItem *item = m->itemFromIndex(index))65 item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));66 } 67 68 void 69 FilterBarComboBoxDelegate :: paint (QPainter * painter,54 FilterBarComboBoxDelegate :: isSeparator (const QModelIndex &index) 55 { 56 return index.data (Qt::AccessibleDescriptionRole).toString () == QLatin1String ("separator"); 57 } 58 void 59 FilterBarComboBoxDelegate :: setSeparator (QAbstractItemModel * model, const QModelIndex& index) 60 { 61 model->setData (index, QString::fromLatin1 ("separator"), Qt::AccessibleDescriptionRole); 62 63 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*> (model)) 64 if (QStandardItem *item = m->itemFromIndex (index)) 65 item->setFlags (item->flags () & ~ (Qt::ItemIsSelectable|Qt::ItemIsEnabled)); 66 } 67 68 void 69 FilterBarComboBoxDelegate :: paint (QPainter * painter, 70 70 const QStyleOptionViewItem & option, 71 const QModelIndex & index 72 { 73 if( isSeparator( index ))74 { 75 76 if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3*>(&option))77 if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(v3->widget))78 rect.setWidth(view->viewport()->width());79 80 81 myCombo->style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, painter, myCombo);82 } 83 84 { 85 86 disabledOption.state &= ~( QStyle::State_Enabled | QStyle::State_Selected);87 88 89 const int hmargin = getHSpacing( myCombo);90 boundingBox.setLeft( boundingBox.left() + hmargin);91 boundingBox.setRight( boundingBox.right() - hmargin);92 93 QRect decorationRect = rect( option, index, Qt::DecorationRole);94 decorationRect.moveLeft( decorationRect.left( ));95 decorationRect.setSize( myCombo->iconSize( ));96 decorationRect = QStyle::alignedRect(Qt::LeftToRight,97 98 decorationRect.size(), boundingBox);99 boundingBox.setLeft( decorationRect.right() + hmargin);100 101 QRect countRect = rect( option, index, TorrentCountRole);102 countRect = QStyle::alignedRect(Qt::LeftToRight,103 104 countRect.size(), boundingBox);105 boundingBox.setRight( countRect.left() - hmargin);106 107 108 drawBackground( painter, option, index);109 110 option2.decorationSize = myCombo->iconSize();111 drawDecoration( painter, option, decorationRect, decoration(option2,index.data(Qt::DecorationRole)));112 drawDisplay( painter, option, displayRect, index.data(Qt::DisplayRole).toString());113 drawDisplay( painter, disabledOption, countRect, index.data(TorrentCountRole).toString());114 drawFocus( painter, option, displayRect|countRect);71 const QModelIndex & index) const 72 { 73 if (isSeparator (index)) 74 { 75 QRect rect = option.rect; 76 if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3*> (&option)) 77 if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView*> (v3->widget)) 78 rect.setWidth (view->viewport ()->width ()); 79 QStyleOption opt; 80 opt.rect = rect; 81 myCombo->style ()->drawPrimitive (QStyle::PE_IndicatorToolBarSeparator, &opt, painter, myCombo); 82 } 83 else 84 { 85 QStyleOptionViewItem disabledOption = option; 86 disabledOption.state &= ~ (QStyle::State_Enabled | QStyle::State_Selected); 87 QRect boundingBox = option.rect; 88 89 const int hmargin = getHSpacing (myCombo); 90 boundingBox.setLeft (boundingBox.left () + hmargin); 91 boundingBox.setRight (boundingBox.right () - hmargin); 92 93 QRect decorationRect = rect (option, index, Qt::DecorationRole); 94 decorationRect.moveLeft (decorationRect.left ()); 95 decorationRect.setSize (myCombo->iconSize ()); 96 decorationRect = QStyle::alignedRect (Qt::LeftToRight, 97 Qt::AlignLeft|Qt::AlignVCenter, 98 decorationRect.size (), boundingBox); 99 boundingBox.setLeft (decorationRect.right () + hmargin); 100 101 QRect countRect = rect (option, index, TorrentCountRole); 102 countRect = QStyle::alignedRect (Qt::LeftToRight, 103 Qt::AlignRight|Qt::AlignVCenter, 104 countRect.size (), boundingBox); 105 boundingBox.setRight (countRect.left () - hmargin); 106 const QRect displayRect = boundingBox; 107 108 drawBackground (painter, option, index); 109 QStyleOptionViewItem option2 = option; 110 option2.decorationSize = myCombo->iconSize (); 111 drawDecoration (painter, option, decorationRect, decoration (option2,index.data (Qt::DecorationRole))); 112 drawDisplay (painter, option, displayRect, index.data (Qt::DisplayRole).toString ()); 113 drawDisplay (painter, disabledOption, countRect, index.data (TorrentCountRole).toString ()); 114 drawFocus (painter, option, displayRect|countRect); 115 115 } 116 116 } 117 117 118 118 QSize 119 FilterBarComboBoxDelegate :: sizeHint (const QStyleOptionViewItem & option,120 const QModelIndex & index 121 { 122 if( isSeparator( index ))123 { 124 const int pm = myCombo->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, myCombo);125 return QSize( pm, pm + 10);126 } 127 128 { 129 QStyle * s = myCombo->style();130 const int hmargin = getHSpacing( myCombo);131 132 QSize size = QItemDelegate::sizeHint( option, index);133 size.setHeight( qMax( size.height(), myCombo->iconSize().height() + 6 ));134 size.rwidth() += s->pixelMetric( QStyle::PM_FocusFrameHMargin, 0, myCombo);135 size.rwidth() += rect(option,index,TorrentCountRole).width();136 size.rwidth() += hmargin * 4;137 119 FilterBarComboBoxDelegate :: sizeHint (const QStyleOptionViewItem & option, 120 const QModelIndex & index) const 121 { 122 if (isSeparator (index)) 123 { 124 const int pm = myCombo->style ()->pixelMetric (QStyle::PM_DefaultFrameWidth, 0, myCombo); 125 return QSize (pm, pm + 10); 126 } 127 else 128 { 129 QStyle * s = myCombo->style (); 130 const int hmargin = getHSpacing (myCombo); 131 132 QSize size = QItemDelegate::sizeHint (option, index); 133 size.setHeight (qMax (size.height (), myCombo->iconSize ().height () + 6)); 134 size.rwidth () += s->pixelMetric (QStyle::PM_FocusFrameHMargin, 0, myCombo); 135 size.rwidth () += rect (option,index,TorrentCountRole).width (); 136 size.rwidth () += hmargin * 4; 137 return size; 138 138 } 139 139 } … … 143 143 **/ 144 144 145 FilterBarComboBox :: FilterBarComboBox( QWidget * parent ): 146 QComboBox( parent ) 147 { 148 } 149 150 void 151 FilterBarComboBox :: paintEvent( QPaintEvent * e ) 152 { 153 Q_UNUSED( e ); 154 155 QStylePainter painter(this); 156 painter.setPen(palette().color(QPalette::Text)); 157 158 // draw the combobox frame, focusrect and selected etc. 159 QStyleOptionComboBox opt; 160 initStyleOption(&opt); 161 painter.drawComplexControl(QStyle::CC_ComboBox, opt); 162 163 // draw the icon and text 164 const QModelIndex modelIndex = model()->index( currentIndex(), 0, rootModelIndex() ); 165 if( modelIndex.isValid( ) ) 166 { 167 QStyle * s = style(); 168 QRect rect = s->subControlRect( QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this ); 169 const int hmargin = getHSpacing( this ); 170 rect.setRight( rect.right() - hmargin ); 171 172 // draw the icon 173 QPixmap pixmap; 174 QVariant variant = modelIndex.data( Qt::DecorationRole ); 175 switch( variant.type( ) ) { 176 case QVariant::Pixmap: pixmap = qvariant_cast<QPixmap>(variant); break; 177 case QVariant::Icon: pixmap = qvariant_cast<QIcon>(variant).pixmap(iconSize()); break; 178 default: break; 179 } 180 if( !pixmap.isNull() ) { 181 s->drawItemPixmap( &painter, rect, Qt::AlignLeft|Qt::AlignVCenter, pixmap ); 182 rect.setLeft( rect.left() + pixmap.width() + hmargin ); 183 } 184 185 // draw the count 186 QString text = modelIndex.data(TorrentCountRole).toString(); 187 if( !text.isEmpty( ) ) 188 { 189 const QPen pen = painter.pen( ); 190 painter.setPen( opt.palette.color( QPalette::Disabled, QPalette::Text ) ); 191 QRect r = s->itemTextRect( painter.fontMetrics(), rect, Qt::AlignRight|Qt::AlignVCenter, false, text ); 192 painter.drawText( r, 0, text ); 193 rect.setRight( r.left() - hmargin ); 194 painter.setPen( pen ); 195 } 196 197 // draw the text 198 text = modelIndex.data( Qt::DisplayRole ).toString(); 199 text = painter.fontMetrics().elidedText ( text, Qt::ElideRight, rect.width() ); 200 s->drawItemText( &painter, rect, Qt::AlignLeft|Qt::AlignVCenter, opt.palette, true, text ); 145 FilterBarComboBox :: FilterBarComboBox (QWidget * parent): 146 QComboBox (parent) 147 { 148 } 149 150 void 151 FilterBarComboBox :: paintEvent (QPaintEvent * e) 152 { 153 Q_UNUSED (e); 154 155 QStylePainter painter (this); 156 painter.setPen (palette ().color (QPalette::Text)); 157 158 // draw the combobox frame, focusrect and selected etc. 159 QStyleOptionComboBox opt; 160 initStyleOption (&opt); 161 painter.drawComplexControl (QStyle::CC_ComboBox, opt); 162 163 // draw the icon and text 164 const QModelIndex modelIndex = model ()->index (currentIndex (), 0, rootModelIndex ()); 165 if (modelIndex.isValid ()) 166 { 167 QStyle * s = style (); 168 QRect rect = s->subControlRect (QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this); 169 const int hmargin = getHSpacing (this); 170 rect.setRight (rect.right () - hmargin); 171 172 // draw the icon 173 QPixmap pixmap; 174 QVariant variant = modelIndex.data (Qt::DecorationRole); 175 switch (variant.type ()) 176 { 177 case QVariant::Pixmap: pixmap = qvariant_cast<QPixmap> (variant); break; 178 case QVariant::Icon: pixmap = qvariant_cast<QIcon> (variant).pixmap (iconSize ()); break; 179 default: break; 180 } 181 if (!pixmap.isNull ()) 182 { 183 s->drawItemPixmap (&painter, rect, Qt::AlignLeft|Qt::AlignVCenter, pixmap); 184 rect.setLeft (rect.left () + pixmap.width () + hmargin); 185 } 186 187 // draw the count 188 QString text = modelIndex.data (TorrentCountRole).toString (); 189 if (!text.isEmpty ()) 190 { 191 const QPen pen = painter.pen (); 192 painter.setPen (opt.palette.color (QPalette::Disabled, QPalette::Text)); 193 QRect r = s->itemTextRect (painter.fontMetrics (), rect, Qt::AlignRight|Qt::AlignVCenter, false, text); 194 painter.drawText (r, 0, text); 195 rect.setRight (r.left () - hmargin); 196 painter.setPen (pen); 197 } 198 199 // draw the text 200 text = modelIndex.data (Qt::DisplayRole).toString (); 201 text = painter.fontMetrics ().elidedText (text, Qt::ElideRight, rect.width ()); 202 s->drawItemText (&painter, rect, Qt::AlignLeft|Qt::AlignVCenter, opt.palette, true, text); 201 203 } 202 204 } … … 209 211 210 212 QComboBox* 211 FilterBar :: createActivityCombo ()212 { 213 QComboBox * c = new FilterBarComboBox( this);214 FilterBarComboBoxDelegate * delegate = new FilterBarComboBoxDelegate( 0, c);215 c->setItemDelegate( delegate);216 217 QPixmap blankPixmap( c->iconSize( ));218 blankPixmap.fill( Qt::transparent);219 QIcon blankIcon( blankPixmap);220 221 222 223 QStandardItem * row = new QStandardItem( tr( "All" ));224 row->setData( FilterMode::SHOW_ALL, ActivityRole);225 model->appendRow( row);226 227 model->appendRow( new QStandardItem); // separator228 delegate->setSeparator( model, model->index( 1, 0 ));229 230 row = new QStandardItem( QIcon::fromTheme( "system-run", blankIcon ), tr( "Active" ));231 row->setData( FilterMode::SHOW_ACTIVE, ActivityRole);232 model->appendRow( row);233 234 row = new QStandardItem( QIcon::fromTheme( "go-down", blankIcon ), tr( "Downloading" ));235 row->setData( FilterMode::SHOW_DOWNLOADING, ActivityRole);236 model->appendRow( row);237 238 row = new QStandardItem( QIcon::fromTheme( "go-up", blankIcon ), tr( "Seeding" ));239 row->setData( FilterMode::SHOW_SEEDING, ActivityRole);240 model->appendRow( row);241 242 row = new QStandardItem( QIcon::fromTheme( "media-playback-pause", blankIcon ), tr( "Paused" ));243 row->setData( FilterMode::SHOW_PAUSED, ActivityRole);244 model->appendRow( row);245 246 row = new QStandardItem( blankIcon, tr( "Finished" ));247 row->setData( FilterMode::SHOW_FINISHED, ActivityRole);248 model->appendRow( row);249 250 row = new QStandardItem( QIcon::fromTheme( "view-refresh", blankIcon ), tr( "Verifying" ));251 row->setData( FilterMode::SHOW_VERIFYING, ActivityRole);252 model->appendRow( row);253 254 row = new QStandardItem( QIcon::fromTheme( "dialog-error", blankIcon ), tr( "Error" ));255 row->setData( FilterMode::SHOW_ERROR, ActivityRole);256 model->appendRow( row);257 258 c->setModel( model);259 213 FilterBar :: createActivityCombo () 214 { 215 QComboBox * c = new FilterBarComboBox (this); 216 FilterBarComboBoxDelegate * delegate = new FilterBarComboBoxDelegate (0, c); 217 c->setItemDelegate (delegate); 218 219 QPixmap blankPixmap (c->iconSize ()); 220 blankPixmap.fill (Qt::transparent); 221 QIcon blankIcon (blankPixmap); 222 223 QStandardItemModel * model = new QStandardItemModel; 224 225 QStandardItem * row = new QStandardItem (tr ("All")); 226 row->setData (FilterMode::SHOW_ALL, ActivityRole); 227 model->appendRow (row); 228 229 model->appendRow (new QStandardItem); // separator 230 delegate->setSeparator (model, model->index (1, 0)); 231 232 row = new QStandardItem (QIcon::fromTheme ("system-run", blankIcon), tr ("Active")); 233 row->setData (FilterMode::SHOW_ACTIVE, ActivityRole); 234 model->appendRow (row); 235 236 row = new QStandardItem (QIcon::fromTheme ("go-down", blankIcon), tr ("Downloading")); 237 row->setData (FilterMode::SHOW_DOWNLOADING, ActivityRole); 238 model->appendRow (row); 239 240 row = new QStandardItem (QIcon::fromTheme ("go-up", blankIcon), tr ("Seeding")); 241 row->setData (FilterMode::SHOW_SEEDING, ActivityRole); 242 model->appendRow (row); 243 244 row = new QStandardItem (QIcon::fromTheme ("media-playback-pause", blankIcon), tr ("Paused")); 245 row->setData (FilterMode::SHOW_PAUSED, ActivityRole); 246 model->appendRow (row); 247 248 row = new QStandardItem (blankIcon, tr ("Finished")); 249 row->setData (FilterMode::SHOW_FINISHED, ActivityRole); 250 model->appendRow (row); 251 252 row = new QStandardItem (QIcon::fromTheme ("view-refresh", blankIcon), tr ("Verifying")); 253 row->setData (FilterMode::SHOW_VERIFYING, ActivityRole); 254 model->appendRow (row); 255 256 row = new QStandardItem (QIcon::fromTheme ("dialog-error", blankIcon), tr ("Error")); 257 row->setData (FilterMode::SHOW_ERROR, ActivityRole); 258 model->appendRow (row); 259 260 c->setModel (model); 261 return c; 260 262 } 261 263 … … 268 270 namespace 269 271 { 270 QString readableHostName( const QString host ) 271 { 272 // get the readable name... 273 QString name = host; 274 const int pos = name.lastIndexOf( '.' ); 275 if( pos >= 0 ) 276 name.truncate( pos ); 277 if( !name.isEmpty( ) ) 278 name[0] = name[0].toUpper( ); 279 return name; 280 } 281 } 282 283 void 284 FilterBar :: refreshTrackers( ) 285 { 286 Favicons& favicons = dynamic_cast<MyApp*>(QApplication::instance())->favicons; 287 const int firstTrackerRow = 2; // skip over the "All" and separator... 288 289 // pull info from the tracker model... 290 QSet<QString> oldHosts; 291 for( int row=firstTrackerRow; ; ++row ) { 292 QModelIndex index = myTrackerModel->index( row, 0 ); 293 if( !index.isValid( ) ) 272 QString readableHostName (const QString host) 273 { 274 // get the readable name... 275 QString name = host; 276 const int pos = name.lastIndexOf ('.'); 277 if (pos >= 0) 278 name.truncate (pos); 279 if (!name.isEmpty ()) 280 name[0] = name[0].toUpper (); 281 return name; 282 } 283 } 284 285 void 286 FilterBar :: refreshTrackers () 287 { 288 Favicons& favicons = dynamic_cast<MyApp*> (QApplication::instance ())->favicons; 289 const int firstTrackerRow = 2; // skip over the "All" and separator... 290 291 // pull info from the tracker model... 292 QSet<QString> oldHosts; 293 for (int row=firstTrackerRow; ; ++row) 294 { 295 QModelIndex index = myTrackerModel->index (row, 0); 296 if (!index.isValid ()) 297 break; 298 oldHosts << index.data (TrackerRole).toString (); 299 } 300 301 // pull the new stats from the torrent model... 302 QSet<QString> newHosts; 303 QMap<QString,int> torrentsPerHost; 304 for (int row=0; ; ++row) 305 { 306 QModelIndex index = myTorrents.index (row, 0); 307 if (!index.isValid ()) 308 break; 309 const Torrent * tor = index.data (TorrentModel::TorrentRole).value<const Torrent*> (); 310 QSet<QString> torrentNames; 311 foreach (QString host, tor->hosts ()) 312 { 313 newHosts.insert (host); 314 torrentNames.insert (readableHostName (host)); 315 } 316 foreach (QString name, torrentNames) 317 ++torrentsPerHost[name]; 318 } 319 320 // update the "All" row 321 myTrackerModel->setData (myTrackerModel->index (0,0), getCountString (myTorrents.rowCount ()), TorrentCountRole); 322 323 // rows to update 324 foreach (QString host, oldHosts & newHosts) 325 { 326 const QString name = readableHostName (host); 327 QStandardItem * row = myTrackerModel->findItems (name).front (); 328 row->setData (getCountString (torrentsPerHost[name]), TorrentCountRole); 329 row->setData (favicons.findFromHost (host), Qt::DecorationRole); 330 } 331 332 // rows to remove 333 foreach (QString host, oldHosts - newHosts) 334 { 335 const QString name = readableHostName (host); 336 QStandardItem * item = myTrackerModel->findItems (name).front (); 337 if (!item->data (TrackerRole).toString ().isEmpty ()) // don't remove "All" 338 myTrackerModel->removeRows (item->row (), 1); 339 } 340 341 // rows to add 342 bool anyAdded = false; 343 foreach (QString host, newHosts - oldHosts) 344 { 345 const QString name = readableHostName (host); 346 347 if (!myTrackerModel->findItems (name).isEmpty ()) 348 continue; 349 350 // find the sorted position to add this row 351 int i = firstTrackerRow; 352 for (int n=myTrackerModel->rowCount (); i<n; ++i) 353 { 354 const QString rowName = myTrackerModel->index (i,0).data (Qt::DisplayRole).toString (); 355 if (rowName >= name) 294 356 break; 295 oldHosts << index.data(TrackerRole).toString(); 296 } 297 298 // pull the new stats from the torrent model... 299 QSet<QString> newHosts; 300 QMap<QString,int> torrentsPerHost; 301 for( int row=0; ; ++row ) 302 { 303 QModelIndex index = myTorrents.index( row, 0 ); 304 if( !index.isValid( ) ) 305 break; 306 const Torrent * tor = index.data( TorrentModel::TorrentRole ).value<const Torrent*>(); 307 QSet<QString> torrentNames; 308 foreach (QString host, tor->hosts()) { 309 newHosts.insert (host); 310 torrentNames.insert (readableHostName(host)); 311 } 312 foreach (QString name, torrentNames) 313 ++torrentsPerHost[name]; 314 } 315 316 // update the "All" row 317 myTrackerModel->setData( myTrackerModel->index(0,0), getCountString(myTorrents.rowCount()), TorrentCountRole ); 318 319 // rows to update 320 foreach( QString host, oldHosts & newHosts ) 321 { 322 const QString name = readableHostName( host ); 323 QStandardItem * row = myTrackerModel->findItems(name).front(); 324 row->setData( getCountString(torrentsPerHost[name]), TorrentCountRole ); 325 row->setData( favicons.findFromHost(host), Qt::DecorationRole ); 326 } 327 328 // rows to remove 329 foreach( QString host, oldHosts - newHosts ) { 330 const QString name = readableHostName( host ); 331 QStandardItem * item = myTrackerModel->findItems(name).front(); 332 if( !item->data(TrackerRole).toString().isEmpty() ) // don't remove "All" 333 myTrackerModel->removeRows( item->row(), 1 ); 334 } 335 336 // rows to add 337 bool anyAdded = false; 338 foreach( QString host, newHosts - oldHosts ) 339 { 340 const QString name = readableHostName( host ); 341 342 if( !myTrackerModel->findItems(name).isEmpty() ) 343 continue; 344 345 // find the sorted position to add this row 346 int i = firstTrackerRow; 347 for( int n=myTrackerModel->rowCount(); i<n; ++i ) { 348 const QString rowName = myTrackerModel->index(i,0).data(Qt::DisplayRole).toString(); 349 if( rowName >= name ) 350 break; 351 } 352 353 // add the row 354 QStandardItem * row = new QStandardItem( favicons.findFromHost( host ), name ); 355 row->setData( getCountString(torrentsPerHost[host]), TorrentCountRole ); 356 row->setData( favicons.findFromHost(host), Qt::DecorationRole ); 357 row->setData( host, TrackerRole ); 358 myTrackerModel->insertRow( i, row ); 359 anyAdded = true; 360 } 361 362 if( anyAdded ) // the one added might match our filter... 363 refreshPref( Prefs::FILTER_TRACKERS ); 357 } 358 359 // add the row 360 QStandardItem * row = new QStandardItem (favicons.findFromHost (host), name); 361 row->setData (getCountString (torrentsPerHost[host]), TorrentCountRole); 362 row->setData (favicons.findFromHost (host), Qt::DecorationRole); 363 row->setData (host, TrackerRole); 364 myTrackerModel->insertRow (i, row); 365 anyAdded = true; 366 } 367 368 if (anyAdded) // the one added might match our filter... 369 refreshPref (Prefs::FILTER_TRACKERS); 364 370 } 365 371 366 372 367 373 QComboBox* 368 FilterBar :: createTrackerCombo ( QStandardItemModel * model)369 { 370 QComboBox * c = new FilterBarComboBox( this);371 FilterBarComboBoxDelegate * delegate = new FilterBarComboBoxDelegate( 0, c);372 c->setItemDelegate( delegate);373 374 QStandardItem * row = new QStandardItem( tr( "All" ));375 row->setData( "", TrackerRole);376 row->setData( getCountString(myTorrents.rowCount()), TorrentCountRole);377 model->appendRow( row);378 379 model->appendRow( new QStandardItem); // separator380 delegate->setSeparator( model, model->index( 1, 0 ));381 382 c->setModel( model);383 374 FilterBar :: createTrackerCombo (QStandardItemModel * model) 375 { 376 QComboBox * c = new FilterBarComboBox (this); 377 FilterBarComboBoxDelegate * delegate = new FilterBarComboBoxDelegate (0, c); 378 c->setItemDelegate (delegate); 379 380 QStandardItem * row = new QStandardItem (tr ("All")); 381 row->setData ("", TrackerRole); 382 row->setData (getCountString (myTorrents.rowCount ()), TorrentCountRole); 383 model->appendRow (row); 384 385 model->appendRow (new QStandardItem); // separator 386 delegate->setSeparator (model, model->index (1, 0)); 387 388 c->setModel (model); 389 return c; 384 390 } 385 391 … … 390 396 ****/ 391 397 392 FilterBar :: FilterBar ( Prefs& prefs, TorrentModel& torrents, TorrentFilter& filter, QWidget * parent):393 QWidget( parent),394 myPrefs( prefs),395 myTorrents( torrents),396 myFilter( filter),397 myRecountTimer( new QTimer( this )),398 myIsBootstrapping( true)399 { 400 QHBoxLayout * h = new QHBoxLayout( this);401 const int hmargin = qMax( int(HIG::PAD), style()->pixelMetric( QStyle::PM_LayoutHorizontalSpacing ));402 403 h->setSpacing( 0);404 h->setContentsMargins( 2, 2, 2, 2);405 h->addWidget( new QLabel( tr( "Show:" ), this ));406 h->addSpacing( hmargin);407 408 myActivityCombo = createActivityCombo();409 h->addWidget( myActivityCombo, 1);410 h->addSpacing( hmargin);411 412 413 myTrackerCombo = createTrackerCombo( myTrackerModel);414 h->addWidget( myTrackerCombo, 1);415 h->addSpacing( hmargin*2);416 417 myLineEdit = new QLineEdit( this);418 h->addWidget( myLineEdit);419 connect( myLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onTextChanged(QString)));420 421 422 QIcon icon = QIcon::fromTheme( "edit-clear", style()->standardIcon( QStyle::SP_DialogCloseButton ));423 int iconSize = style()->pixelMetric( QStyle::PM_SmallIconSize);424 p->setIconSize( QSize( iconSize, iconSize ));425 p->setIcon( icon);426 p->setFlat( true);427 h->addWidget( p);428 connect( p, SIGNAL(clicked(bool)), myLineEdit, SLOT(clear()));429 430 431 connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(int)));432 connect( myActivityCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onActivityIndexChanged(int)));433 connect( myTrackerCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onTrackerIndexChanged(int)));434 connect( &myTorrents, SIGNAL(modelReset()), this, SLOT(onTorrentModelReset()));435 connect( &myTorrents, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(onTorrentModelRowsInserted(const QModelIndex&,int,int)));436 connect( &myTorrents, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(onTorrentModelRowsRemoved(const QModelIndex&,int,int)));437 connect( &myTorrents, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)), this, SLOT(onTorrentModelDataChanged(const QModelIndex&,const QModelIndex&)));438 connect( myRecountTimer, SIGNAL(timeout()), this, SLOT(recount()));439 440 recountSoon();441 refreshTrackers();442 443 444 445 446 447 448 foreach( int key, initKeys)449 refreshPref( key);450 } 451 452 FilterBar :: ~FilterBar ()453 { 454 398 FilterBar :: FilterBar (Prefs& prefs, TorrentModel& torrents, TorrentFilter& filter, QWidget * parent): 399 QWidget (parent), 400 myPrefs (prefs), 401 myTorrents (torrents), 402 myFilter (filter), 403 myRecountTimer (new QTimer (this)), 404 myIsBootstrapping (true) 405 { 406 QHBoxLayout * h = new QHBoxLayout (this); 407 const int hmargin = qMax (int (HIG::PAD), style ()->pixelMetric (QStyle::PM_LayoutHorizontalSpacing)); 408 409 h->setSpacing (0); 410 h->setContentsMargins (2, 2, 2, 2); 411 h->addWidget (new QLabel (tr ("Show:"), this)); 412 h->addSpacing (hmargin); 413 414 myActivityCombo = createActivityCombo (); 415 h->addWidget (myActivityCombo, 1); 416 h->addSpacing (hmargin); 417 418 myTrackerModel = new QStandardItemModel; 419 myTrackerCombo = createTrackerCombo (myTrackerModel); 420 h->addWidget (myTrackerCombo, 1); 421 h->addSpacing (hmargin*2); 422 423 myLineEdit = new QLineEdit (this); 424 h->addWidget (myLineEdit); 425 connect (myLineEdit, SIGNAL (textChanged (QString)), this, SLOT (onTextChanged (QString))); 426 427 QPushButton * p = new QPushButton; 428 QIcon icon = QIcon::fromTheme ("edit-clear", style ()->standardIcon (QStyle::SP_DialogCloseButton)); 429 int iconSize = style ()->pixelMetric (QStyle::PM_SmallIconSize); 430 p->setIconSize (QSize (iconSize, iconSize)); 431 p->setIcon (icon); 432 p->setFlat (true); 433 h->addWidget (p); 434 connect (p, SIGNAL (clicked (bool)), myLineEdit, SLOT (clear ())); 435 436 // listen for changes from the other players 437 connect (&myPrefs, SIGNAL (changed (int)), this, SLOT (refreshPref (int))); 438 connect (myActivityCombo, SIGNAL (currentIndexChanged (int)), this, SLOT (onActivityIndexChanged (int))); 439 connect (myTrackerCombo, SIGNAL (currentIndexChanged (int)), this, SLOT (onTrackerIndexChanged (int))); 440 connect (&myTorrents, SIGNAL (modelReset ()), this, SLOT (onTorrentModelReset ())); 441 connect (&myTorrents, SIGNAL (rowsInserted (const QModelIndex&,int,int)), this, SLOT (onTorrentModelRowsInserted (const QModelIndex&,int,int))); 442 connect (&myTorrents, SIGNAL (rowsRemoved (const QModelIndex&,int,int)), this, SLOT (onTorrentModelRowsRemoved (const QModelIndex&,int,int))); 443 connect (&myTorrents, SIGNAL (dataChanged (const QModelIndex&,const QModelIndex&)), this, SLOT (onTorrentModelDataChanged (const QModelIndex&,const QModelIndex&))); 444 connect (myRecountTimer, SIGNAL (timeout ()), this, SLOT (recount ())); 445 446 recountSoon (); 447 refreshTrackers (); 448 myIsBootstrapping = false; 449 450 // initialize our state 451 QList<int> initKeys; 452 initKeys << Prefs :: FILTER_MODE 453 << Prefs :: FILTER_TRACKERS; 454 foreach (int key, initKeys) 455 refreshPref (key); 456 } 457 458 FilterBar :: ~FilterBar () 459 { 460 delete myRecountTimer; 455 461 } 456 462 … … 460 466 461 467 void 462 FilterBar :: refreshPref( int key ) 463 { 464 switch( key ) 465 { 466 case Prefs :: FILTER_MODE: { 467 const FilterMode m = myPrefs.get<FilterMode>( key ); 468 QAbstractItemModel * model = myActivityCombo->model( ); 469 QModelIndexList indices = model->match( model->index(0,0), ActivityRole, m.mode() ); 470 myActivityCombo->setCurrentIndex( indices.isEmpty() ? 0 : indices.first().row( ) ); 471 break; 472 } 473 474 case Prefs :: FILTER_TRACKERS: { 475 const QString tracker = myPrefs.getString( key ); 476 const QString name = readableHostName( tracker ); 477 QList<QStandardItem*> rows = myTrackerModel->findItems(name); 478 if( !rows.isEmpty() ) 479 myTrackerCombo->setCurrentIndex( rows.front()->row() ); 480 else { // hm, we don't seem to have this tracker anymore... 481 const bool isBootstrapping = myTrackerModel->rowCount( ) <= 2; 482 if( !isBootstrapping ) 483 myPrefs.set( key, "" ); 468 FilterBar :: refreshPref (int key) 469 { 470 switch (key) 471 { 472 case Prefs :: FILTER_MODE: 473 { 474 const FilterMode m = myPrefs.get<FilterMode> (key); 475 QAbstractItemModel * model = myActivityCombo->model (); 476 QModelIndexList indices = model->match (model->index (0,0), ActivityRole, m.mode ()); 477 myActivityCombo->setCurrentIndex (indices.isEmpty () ? 0 : indices.first ().row ()); 478 break; 479 } 480 481 case Prefs :: FILTER_TRACKERS: 482 { 483 const QString tracker = myPrefs.getString (key); 484 const QString name = readableHostName (tracker); 485 QList<QStandardItem*> rows = myTrackerModel->findItems (name); 486 if (!rows.isEmpty ()) 487 { 488 myTrackerCombo->setCurrentIndex (rows.front ()->row ()); 484 489 } 485 break; 486 } 487 } 488 } 489 490 void 491 FilterBar :: onTextChanged( const QString& str ) 492 { 493 if( !myIsBootstrapping ) 494 myPrefs.set( Prefs::FILTER_TEXT, str.trimmed( ) ); 495 } 496 497 void 498 FilterBar :: onTrackerIndexChanged( int i ) 499 { 500 if( !myIsBootstrapping ) 501 { 502 QString str; 503 const bool isTracker = !myTrackerCombo->itemData(i,TrackerRole).toString().isEmpty(); 504 if( !isTracker ) // show all 505 str = ""; 506 else { 507 str = myTrackerCombo->itemData(i,TrackerRole).toString(); 508 const int pos = str.lastIndexOf( '.' ); 509 if( pos >= 0 ) 510 str.truncate( pos+1 ); 511 } 512 myPrefs.set( Prefs::FILTER_TRACKERS, str ); 513 } 514 } 515 516 void 517 FilterBar :: onActivityIndexChanged( int i ) 518 { 519 if( !myIsBootstrapping ) 520 { 521 const FilterMode mode = myActivityCombo->itemData( i, ActivityRole ).toInt( ); 522 myPrefs.set( Prefs::FILTER_MODE, mode ); 490 else // hm, we don't seem to have this tracker anymore... 491 { 492 const bool isBootstrapping = myTrackerModel->rowCount () <= 2; 493 if (!isBootstrapping) 494 myPrefs.set (key, ""); 495 } 496 break; 497 } 498 } 499 } 500 501 void 502 FilterBar :: onTextChanged (const QString& str) 503 { 504 if (!myIsBootstrapping) 505 myPrefs.set (Prefs::FILTER_TEXT, str.trimmed ()); 506 } 507 508 void 509 FilterBar :: onTrackerIndexChanged (int i) 510 { 511 if (!myIsBootstrapping) 512 { 513 QString str; 514 const bool isTracker = !myTrackerCombo->itemData (i,TrackerRole).toString ().isEmpty (); 515 if (!isTracker) // show all 516 { 517 str = ""; 518 } 519 else 520 { 521 str = myTrackerCombo->itemData (i,TrackerRole).toString (); 522 const int pos = str.lastIndexOf ('.'); 523 if (pos >= 0) 524 str.truncate (pos+1); 525 } 526 myPrefs.set (Prefs::FILTER_TRACKERS, str); 527 } 528 } 529 530 void 531 FilterBar :: onActivityIndexChanged (int i) 532 { 533 if (!myIsBootstrapping) 534 { 535 const FilterMode mode = myActivityCombo->itemData (i, ActivityRole).toInt (); 536 myPrefs.set (Prefs::FILTER_MODE, mode); 523 537 } 524 538 } … … 528 542 ***/ 529 543 530 void FilterBar :: onTorrentModelReset ( ) { recountSoon(); }531 void FilterBar :: onTorrentModelRowsInserted ( const QModelIndex&, int, int ) { recountSoon(); }532 void FilterBar :: onTorrentModelRowsRemoved ( const QModelIndex&, int, int ) { recountSoon(); }533 void FilterBar :: onTorrentModelDataChanged ( const QModelIndex&, const QModelIndex& ) { recountSoon(); }534 535 void 536 FilterBar :: recountSoon ()537 { 538 if( !myRecountTimer->isActive( ))539 { 540 myRecountTimer->setSingleShot( true);541 myRecountTimer->start( 800);544 void FilterBar :: onTorrentModelReset () { recountSoon (); } 545 void FilterBar :: onTorrentModelRowsInserted (const QModelIndex&, int, int) { recountSoon (); } 546 void FilterBar :: onTorrentModelRowsRemoved (const QModelIndex&, int, int) { recountSoon (); } 547 void FilterBar :: onTorrentModelDataChanged (const QModelIndex&, const QModelIndex&) { recountSoon (); } 548 549 void 550 FilterBar :: recountSoon () 551 { 552 if (!myRecountTimer->isActive ()) 553 { 554 myRecountTimer->setSingleShot (true); 555 myRecountTimer->start (800); 542 556 } 543 557 } … … 545 559 FilterBar :: recount () 546 560 { 547 QAbstractItemModel * model = myActivityCombo->model ();561 QAbstractItemModel * model = myActivityCombo->model (); 548 562 549 563 int torrentsPerMode[FilterMode::NUM_MODES] = { }; 550 564 myFilter.countTorrentsPerMode (torrentsPerMode); 551 565 552 for (int row=0, n=model->rowCount (); row<n; ++row)566 for (int row=0, n=model->rowCount (); row<n; ++row) 553 567 { 554 568 QModelIndex index = model->index (row, 0); 555 const int mode = index.data (ActivityRole).toInt();556 model->setData (index, getCountString (torrentsPerMode[mode]), TorrentCountRole);569 const int mode = index.data (ActivityRole).toInt (); 570 model->setData (index, getCountString (torrentsPerMode[mode]), TorrentCountRole); 557 571 } 558 572 … … 561 575 562 576 QString 563 FilterBar :: getCountString ( int n) const564 { 565 return QString("%L1").arg(n);566 } 577 FilterBar :: getCountString (int n) const 578 { 579 return QString ("%L1").arg (n); 580 } -
trunk/qt/filterbar.h
r11406 r13869 29 29 class FilterBarComboBoxDelegate: public QItemDelegate 30 30 { 31 31 Q_OBJECT 32 32 33 34 FilterBarComboBoxDelegate( QObject * parent, QComboBox * combo);33 public: 34 FilterBarComboBoxDelegate (QObject * parent, QComboBox * combo); 35 35 36 37 static bool isSeparator( const QModelIndex &index);38 static void setSeparator( QAbstractItemModel * model, const QModelIndex& index);36 public: 37 static bool isSeparator (const QModelIndex &index); 38 static void setSeparator (QAbstractItemModel * model, const QModelIndex& index); 39 39 40 41 virtual void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex&) const;42 virtual QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex&) const;40 protected: 41 virtual void paint (QPainter*, const QStyleOptionViewItem&, const QModelIndex&) const; 42 virtual QSize sizeHint (const QStyleOptionViewItem&, const QModelIndex&) const; 43 43 44 45 44 private: 45 QComboBox * myCombo; 46 46 47 47 }; … … 49 49 class FilterBarComboBox: public QComboBox 50 50 { 51 51 Q_OBJECT 52 52 53 54 FilterBarComboBox( QWidget * parent = 0);53 public: 54 FilterBarComboBox (QWidget * parent = 0); 55 55 56 57 virtual void paintEvent( QPaintEvent * e);56 protected: 57 virtual void paintEvent (QPaintEvent * e); 58 58 }; 59 59 … … 61 61 class FilterBar: public QWidget 62 62 { 63 63 Q_OBJECT 64 64 65 66 FilterBar( Prefs& prefs, TorrentModel& torrents, TorrentFilter& filter, QWidget * parent = 0);67 ~FilterBar();65 public: 66 FilterBar (Prefs& prefs, TorrentModel& torrents, TorrentFilter& filter, QWidget * parent = 0); 67 ~FilterBar (); 68 68 69 70 QComboBox * createTrackerCombo( QStandardItemModel *);71 QComboBox * createActivityCombo();72 void recountSoon();73 void refreshTrackers();74 QString getCountString( int n) const;69 private: 70 QComboBox * createTrackerCombo (QStandardItemModel * ); 71 QComboBox * createActivityCombo (); 72 void recountSoon (); 73 void refreshTrackers (); 74 QString getCountString (int n) const; 75 75 76 77 78 79 80 81 82 83 84 85 76 private: 77 Prefs& myPrefs; 78 TorrentModel& myTorrents; 79 TorrentFilter& myFilter; 80 QComboBox * myActivityCombo; 81 QComboBox * myTrackerCombo; 82 QStandardItemModel * myTrackerModel; 83 QTimer * myRecountTimer; 84 bool myIsBootstrapping; 85 QLineEdit * myLineEdit; 86 86 87 88 void recount();89 void refreshPref( int key);90 void onActivityIndexChanged( int index);91 void onTrackerIndexChanged( int index);92 void onTorrentModelReset();93 void onTorrentModelRowsInserted( const QModelIndex&, int, int);94 void onTorrentModelRowsRemoved( const QModelIndex&, int, int);95 void onTorrentModelDataChanged( const QModelIndex&, const QModelIndex&);96 void onTextChanged( const QString&);87 private slots: 88 void recount (); 89 void refreshPref (int key); 90 void onActivityIndexChanged (int index); 91 void onTrackerIndexChanged (int index); 92 void onTorrentModelReset (); 93 void onTorrentModelRowsInserted (const QModelIndex&, int, int); 94 void onTorrentModelRowsRemoved (const QModelIndex&, int, int); 95 void onTorrentModelDataChanged (const QModelIndex&, const QModelIndex&); 96 void onTextChanged (const QString&); 97 97 }; 98 98 -
trunk/qt/prefs.h
r13813 r13869 31 31 class Prefs: public QObject 32 32 { 33 33 Q_OBJECT; 34 34 35 35 public: 36 36 37 enum 37 enum 38 { 39 /* client prefs */ 40 OPTIONS_PROMPT, 41 OPEN_DIALOG_FOLDER, 42 INHIBIT_HIBERNATION, 43 DIR_WATCH, 44 DIR_WATCH_ENABLED, 45 SHOW_TRAY_ICON, 46 START_MINIMIZED, 47 SHOW_NOTIFICATION_ON_ADD, 48 SHOW_NOTIFICATION_ON_COMPLETE, 49 ASKQUIT, 50 SORT_MODE, 51 SORT_REVERSED, 52 COMPACT_VIEW, 53 FILTERBAR, 54 STATUSBAR, 55 STATUSBAR_STATS, 56 SHOW_TRACKER_SCRAPES, 57 SHOW_BACKUP_TRACKERS, 58 TOOLBAR, 59 BLOCKLIST_DATE, 60 BLOCKLIST_UPDATES_ENABLED, 61 MAIN_WINDOW_LAYOUT_ORDER, 62 MAIN_WINDOW_HEIGHT, 63 MAIN_WINDOW_WIDTH, 64 MAIN_WINDOW_X, 65 MAIN_WINDOW_Y, 66 FILTER_MODE, 67 FILTER_TRACKERS, 68 FILTER_TEXT, 69 SESSION_IS_REMOTE, 70 SESSION_REMOTE_HOST, 71 SESSION_REMOTE_PORT, 72 SESSION_REMOTE_AUTH, 73 SESSION_REMOTE_USERNAME, 74 SESSION_REMOTE_PASSWORD, 75 COMPLETE_SOUND_COMMAND, 76 COMPLETE_SOUND_ENABLED, 77 USER_HAS_GIVEN_INFORMED_CONSENT, 78 79 /* core prefs */ 80 FIRST_CORE_PREF, 81 ALT_SPEED_LIMIT_UP = FIRST_CORE_PREF, 82 ALT_SPEED_LIMIT_DOWN, 83 ALT_SPEED_LIMIT_ENABLED, 84 ALT_SPEED_LIMIT_TIME_BEGIN, 85 ALT_SPEED_LIMIT_TIME_END, 86 ALT_SPEED_LIMIT_TIME_ENABLED, 87 ALT_SPEED_LIMIT_TIME_DAY, 88 BLOCKLIST_ENABLED, 89 BLOCKLIST_URL, 90 DSPEED, 91 DSPEED_ENABLED, 92 DOWNLOAD_DIR, 93 DOWNLOAD_QUEUE_ENABLED, 94 DOWNLOAD_QUEUE_SIZE, 95 ENCRYPTION, 96 IDLE_LIMIT, 97 IDLE_LIMIT_ENABLED, 98 INCOMPLETE_DIR, 99 INCOMPLETE_DIR_ENABLED, 100 MSGLEVEL, 101 PEER_LIMIT_GLOBAL, 102 PEER_LIMIT_TORRENT, 103 PEER_PORT, 104 PEER_PORT_RANDOM_ON_START, 105 PEER_PORT_RANDOM_LOW, 106 PEER_PORT_RANDOM_HIGH, 107 QUEUE_STALLED_MINUTES, 108 SCRIPT_TORRENT_DONE_ENABLED, 109 SCRIPT_TORRENT_DONE_FILENAME, 110 SOCKET_TOS, 111 START, 112 TRASH_ORIGINAL, 113 PEX_ENABLED, 114 DHT_ENABLED, 115 UTP_ENABLED, 116 LPD_ENABLED, 117 PORT_FORWARDING, 118 PREALLOCATION, 119 RATIO, 120 RATIO_ENABLED, 121 RENAME_PARTIAL_FILES, 122 RPC_AUTH_REQUIRED, 123 RPC_ENABLED, 124 RPC_PASSWORD, 125 RPC_PORT, 126 RPC_USERNAME, 127 RPC_WHITELIST_ENABLED, 128 RPC_WHITELIST, 129 USPEED_ENABLED, 130 USPEED, 131 UPLOAD_SLOTS_PER_TORRENT, 132 LAST_CORE_PREF = UPLOAD_SLOTS_PER_TORRENT, 133 134 PREFS_COUNT 135 }; 136 137 private: 138 139 struct PrefItem 140 { 141 int id; 142 tr_quark key; 143 int type; 144 }; 145 146 static PrefItem myItems[]; 147 148 private: 149 QSet<int> myTemporaryPrefs; 150 QString myConfigDir; 151 mutable QVariant myValues[PREFS_COUNT]; 152 void initDefaults (struct tr_variant*); 153 154 public: 155 bool isCore (int key) const { return FIRST_CORE_PREF<=key && key<=LAST_CORE_PREF; } 156 bool isClient (int key) const { return !isCore (key); } 157 const char * keyStr (int i) const { return tr_quark_get_string (myItems[i].key,NULL); } 158 tr_quark getKey (int i) const { return myItems[i].key; } 159 int type (int i) const { return myItems[i].type; } 160 const QVariant& variant (int i) const { return myValues[i]; } 161 162 Prefs (const char * configDir); 163 ~Prefs (); 164 165 int getInt (int key) const; 166 bool getBool (int key) const; 167 QString getString (int key) const; 168 double getDouble (int key) const; 169 QDateTime getDateTime (int key) const; 170 171 template<typename T> T get (int key) const { return myValues[key].value<T>(); } 172 173 void set (int key, char * value) { set (key, QString::fromUtf8 (value)); } 174 void set (int key, const char * value) { set (key, QString::fromUtf8 (value)); } 175 176 template<typename T> void set (int key, const T& value) 177 { 178 QVariant& v (myValues[key]); 179 const QVariant tmp = QVariant::fromValue (value); 180 if (v.isNull() || (v!=tmp)) 38 181 { 39 /* client prefs */ 40 OPTIONS_PROMPT, 41 OPEN_DIALOG_FOLDER, 42 INHIBIT_HIBERNATION, 43 DIR_WATCH, 44 DIR_WATCH_ENABLED, 45 SHOW_TRAY_ICON, 46 START_MINIMIZED, 47 SHOW_NOTIFICATION_ON_ADD, 48 SHOW_NOTIFICATION_ON_COMPLETE, 49 ASKQUIT, 50 SORT_MODE, 51 SORT_REVERSED, 52 COMPACT_VIEW, 53 FILTERBAR, 54 STATUSBAR, 55 STATUSBAR_STATS, 56 SHOW_TRACKER_SCRAPES, 57 SHOW_BACKUP_TRACKERS, 58 TOOLBAR, 59 BLOCKLIST_DATE, 60 BLOCKLIST_UPDATES_ENABLED, 61 MAIN_WINDOW_LAYOUT_ORDER, 62 MAIN_WINDOW_HEIGHT, 63 MAIN_WINDOW_WIDTH, 64 MAIN_WINDOW_X, 65 MAIN_WINDOW_Y, 66 FILTER_MODE, 67 FILTER_TRACKERS, 68 FILTER_TEXT, 69 SESSION_IS_REMOTE, 70 SESSION_REMOTE_HOST, 71 SESSION_REMOTE_PORT, 72 SESSION_REMOTE_AUTH, 73 SESSION_REMOTE_USERNAME, 74 SESSION_REMOTE_PASSWORD, 75 COMPLETE_SOUND_COMMAND, 76 COMPLETE_SOUND_ENABLED, 77 USER_HAS_GIVEN_INFORMED_CONSENT, 182 v = tmp; 183 emit changed (key); 184 } 185 } 78 186 79 /* core prefs */ 80 FIRST_CORE_PREF, 81 ALT_SPEED_LIMIT_UP = FIRST_CORE_PREF, 82 ALT_SPEED_LIMIT_DOWN, 83 ALT_SPEED_LIMIT_ENABLED, 84 ALT_SPEED_LIMIT_TIME_BEGIN, 85 ALT_SPEED_LIMIT_TIME_END, 86 ALT_SPEED_LIMIT_TIME_ENABLED, 87 ALT_SPEED_LIMIT_TIME_DAY, 88 BLOCKLIST_ENABLED, 89 BLOCKLIST_URL, 90 DSPEED, 91 DSPEED_ENABLED, 92 DOWNLOAD_DIR, 93 DOWNLOAD_QUEUE_ENABLED, 94 DOWNLOAD_QUEUE_SIZE, 95 ENCRYPTION, 96 IDLE_LIMIT, 97 IDLE_LIMIT_ENABLED, 98 INCOMPLETE_DIR, 99 INCOMPLETE_DIR_ENABLED, 100 MSGLEVEL, 101 PEER_LIMIT_GLOBAL, 102 PEER_LIMIT_TORRENT, 103 PEER_PORT, 104 PEER_PORT_RANDOM_ON_START, 105 PEER_PORT_RANDOM_LOW, 106 PEER_PORT_RANDOM_HIGH, 107 QUEUE_STALLED_MINUTES, 108 SCRIPT_TORRENT_DONE_ENABLED, 109 SCRIPT_TORRENT_DONE_FILENAME, 110 SOCKET_TOS, 111 START, 112 TRASH_ORIGINAL, 113 PEX_ENABLED, 114 DHT_ENABLED, 115 UTP_ENABLED, 116 LPD_ENABLED, 117 PORT_FORWARDING, 118 PREALLOCATION, 119 RATIO, 120 RATIO_ENABLED, 121 RENAME_PARTIAL_FILES, 122 RPC_AUTH_REQUIRED, 123 RPC_ENABLED, 124 RPC_PASSWORD, 125 RPC_PORT, 126 RPC_USERNAME, 127 RPC_WHITELIST_ENABLED, 128 RPC_WHITELIST, 129 USPEED_ENABLED, 130 USPEED, 131 UPLOAD_SLOTS_PER_TORRENT, 132 LAST_CORE_PREF = UPLOAD_SLOTS_PER_TORRENT, 187 void toggleBool (int key); 133 188 134 PREFS_COUNT 135 }; 136 137 private: 138 139 struct PrefItem { 140 int id; 141 tr_quark key; 142 int type; 143 }; 144 145 static PrefItem myItems[]; 146 147 private: 148 QSet<int> myTemporaryPrefs; 149 QString myConfigDir; 150 mutable QVariant myValues[PREFS_COUNT]; 151 void initDefaults( struct tr_variant* ); 152 153 public: 154 bool isCore( int key ) const { return FIRST_CORE_PREF<=key && key<=LAST_CORE_PREF; } 155 bool isClient( int key ) const { return !isCore( key ); } 156 const char * keyStr( int i ) const { return tr_quark_get_string(myItems[i].key,NULL); } 157 tr_quark getKey (int i) const { return myItems[i].key; } 158 int type( int i ) const { return myItems[i].type; } 159 const QVariant& variant( int i ) const { return myValues[i]; } 160 161 Prefs( const char * configDir ); 162 ~Prefs( ); 163 164 int getInt( int key ) const; 165 bool getBool( int key) const; 166 QString getString( int key ) const; 167 double getDouble( int key) const; 168 QDateTime getDateTime( int key ) const; 169 170 template<typename T> T get( int key ) const { 171 return myValues[key].value<T>(); 172 } 173 174 void set( int key, char * value ) { set( key, QString::fromUtf8(value) ); } 175 void set( int key, const char * value ) { set( key, QString::fromUtf8(value) ); } 176 177 template<typename T> void set( int key, const T& value ) { 178 QVariant& v( myValues[key] ); 179 const QVariant tmp = QVariant::fromValue(value); 180 if( v.isNull() || (v!=tmp) ) { 181 v = tmp; 182 emit changed( key ); 183 } 184 } 185 186 void toggleBool( int key ); 187 188 signals: 189 void changed( int key ); 189 signals: 190 void changed (int key); 190 191 }; 191 192
Note: See TracChangeset
for help on using the changeset viewer.