Changeset 14001
- Timestamp:
- Feb 9, 2013, 9:47:42 PM (9 years ago)
- Location:
- trunk/qt
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/qt/options.cc
r14000 r14001 48 48 49 49 void 50 FileAdded :: executed( int64_t tag, const QString& result, struct tr_variant * arguments ) 51 { 52 Q_UNUSED( arguments ); 53 54 if( tag != myTag ) 55 return; 56 57 if( ( result == "success" ) && !myDelFile.isEmpty( ) ) { 58 QFile file( myDelFile ); 59 file.setPermissions( QFile::ReadOwner | QFile::WriteOwner ); 60 file.remove(); 61 } 62 63 if( result != "success" ) { 64 QString text = result; 65 for( int i=0, n=text.size(); i<n; ++i ) 66 if( !i || text[i-1].isSpace() ) 67 text[i] = text[i].toUpper(); 68 QMessageBox::warning( QApplication::activeWindow(), 69 tr( "Error Adding Torrent" ), 70 QString("<p><b>%1</b></p><p>%2</p>").arg(text).arg(myName) ); 71 } 72 73 deleteLater(); 50 FileAdded :: executed (int64_t tag, const QString& result, struct tr_variant * arguments) 51 { 52 Q_UNUSED (arguments); 53 54 if (tag != myTag) 55 return; 56 57 if ( (result == "success") && !myDelFile.isEmpty ()) 58 { 59 QFile file (myDelFile); 60 file.setPermissions (QFile::ReadOwner | QFile::WriteOwner); 61 file.remove (); 62 } 63 64 if (result != "success") 65 { 66 QString text = result; 67 68 for (int i=0, n=text.size (); i<n; ++i) 69 if (!i || text[i-1].isSpace ()) 70 text[i] = text[i].toUpper (); 71 72 QMessageBox::warning (QApplication::activeWindow (), 73 tr ("Error Adding Torrent"), 74 QString ("<p><b>%1</b></p><p>%2</p>").arg (text).arg (myName)); 75 } 76 77 deleteLater (); 74 78 } 75 79 … … 78 82 ***/ 79 83 80 Options :: Options ( Session& session, const Prefs& prefs, const AddData& addme, QWidget * parent):81 QDialog( parent, Qt::Dialog),82 mySession( session),83 myAdd( addme),84 myHaveInfo( false),85 myDestinationButton( 0),86 myVerifyButton( 0),87 myVerifyFile( 0),88 myVerifyHash( QCryptographicHash::Sha1),89 90 { 91 setWindowTitle( tr( "Open Torrent" ));92 QFontMetrics fontMetrics( font( ));93 QGridLayout * layout = new QGridLayout( this);94 95 96 97 98 connect (&myEditTimer, SIGNAL(timeout()), this, SLOT(onDestinationEditedIdle()));99 100 const int iconSize( style( )->pixelMetric( QStyle :: PM_SmallIconSize ));101 QIcon fileIcon = style( )->standardIcon( QStyle::SP_FileIcon);102 const QPixmap filePixmap = fileIcon.pixmap( iconSize);103 104 105 int width = fontMetrics.size( 0, QString::fromAscii( "This is a pretty long torrent filename indeed.torrent" ) ).width();106 QLabel * l = new QLabel( tr( "&Torrent file:" ));107 layout->addWidget( l, row, 0, Qt::AlignLeft);108 109 p->setIcon( filePixmap);110 p->setMinimumWidth( width);111 p->setStyleSheet( QString::fromAscii( "text-align: left; padding-left: 5; padding-right: 5" ));112 p->installEventFilter( this);113 114 layout->addWidget( p, row, 1);115 l->setBuddy( p);116 connect( p, SIGNAL(clicked(bool)), this, SLOT(onFilenameClicked()));117 118 119 const QIcon folderIcon = iconProvider.icon( QFileIconProvider::Folder);120 const QPixmap folderPixmap = folderIcon.pixmap( iconSize);121 122 l = new QLabel( tr( "&Destination folder:" ));123 layout->addWidget( l, ++row, 0, Qt::AlignLeft);124 125 126 127 if( session.isLocal( ))128 { 129 130 131 p->setIcon( folderPixmap);132 p->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5");133 p->installEventFilter( this);134 layout->addWidget( p, row, 1);135 l->setBuddy( p);136 connect( p, SIGNAL(clicked(bool)), this, SLOT(onDestinationClicked()));137 } 138 139 { 140 141 142 layout->addWidget( e, row, 1);143 l->setBuddy( e);144 connect (e, SIGNAL(textEdited(const QString&)), this, SLOT(onDestinationEdited(const QString&)));145 } 146 147 148 149 layout->setRowMinimumHeight (row, l->height() + HIG::PAD_SMALL);150 151 152 layout->addWidget( myTree, ++row, 0, 1, 2);153 if( !session.isLocal( ))154 myTree->hideColumn( 2); // hide the % done, since we've no way of knowing155 156 157 m->addItem( tr( "High" ), TR_PRI_HIGH);158 m->addItem( tr( "Normal" ), TR_PRI_NORMAL);159 m->addItem( tr( "Low" ), TR_PRI_LOW);160 m->setCurrentIndex( 1); // Normal161 162 l = new QLabel( tr( "Torrent &priority:" ));163 l->setBuddy( m);164 layout->addWidget( l, ++row, 0, Qt::AlignLeft);165 layout->addWidget( m, row, 1);166 167 if( session.isLocal( ))168 { 169 p = myVerifyButton = new QPushButton( tr( "&Verify Local Data" ));170 layout->addWidget( p, ++row, 0, Qt::AlignLeft);171 } 172 173 174 c = myStartCheck = new QCheckBox( tr( "&Start when added" ));175 c->setChecked( prefs.getBool( Prefs :: START ));176 layout->addWidget( c, ++row, 0, 1, 2, Qt::AlignLeft);177 178 c = myTrashCheck = new QCheckBox( tr( "Mo&ve .torrent file to the trash" ));179 c->setChecked( prefs.getBool( Prefs :: TRASH_ORIGINAL ));180 layout->addWidget( c, ++row, 0, 1, 2, Qt::AlignLeft);181 182 QDialogButtonBox * b = new QDialogButtonBox( QDialogButtonBox::Open|QDialogButtonBox::Cancel, Qt::Horizontal, this);183 connect( b, SIGNAL(rejected()), this, SLOT(deleteLater()));184 connect( b, SIGNAL(accepted()), this, SLOT(onAccepted()));185 layout->addWidget( b, ++row, 0, 1, 2);186 187 layout->setRowStretch( 3, 2);188 layout->setColumnStretch( 1, 2);189 layout->setSpacing( HIG :: PAD);190 191 connect( myTree, SIGNAL(priorityChanged(const QSet<int>&,int)), this, SLOT(onPriorityChanged(const QSet<int>&,int)));192 connect( myTree, SIGNAL(wantedChanged(const QSet<int>&,bool)), this, SLOT(onWantedChanged(const QSet<int>&,bool)));193 if( session.isLocal( ))194 connect( myVerifyButton, SIGNAL(clicked(bool)), this, SLOT(onVerify()));195 196 connect( &myVerifyTimer, SIGNAL(timeout()), this, SLOT(onTimeout()));197 198 reload();199 } 200 201 Options :: ~Options ()202 { 203 clearInfo();84 Options :: Options (Session& session, const Prefs& prefs, const AddData& addme, QWidget * parent): 85 QDialog (parent, Qt::Dialog), 86 mySession (session), 87 myAdd (addme), 88 myHaveInfo (false), 89 myDestinationButton (0), 90 myVerifyButton (0), 91 myVerifyFile (0), 92 myVerifyHash (QCryptographicHash::Sha1), 93 myEditTimer (this) 94 { 95 setWindowTitle (tr ("Open Torrent")); 96 QFontMetrics fontMetrics (font ()); 97 QGridLayout * layout = new QGridLayout (this); 98 int row = 0; 99 100 myEditTimer.setInterval (2000); 101 myEditTimer.setSingleShot (true); 102 connect (&myEditTimer, SIGNAL (timeout ()), this, SLOT (onDestinationEditedIdle ())); 103 104 const int iconSize (style ()->pixelMetric (QStyle :: PM_SmallIconSize)); 105 QIcon fileIcon = style ()->standardIcon (QStyle::SP_FileIcon); 106 const QPixmap filePixmap = fileIcon.pixmap (iconSize); 107 108 QPushButton * p; 109 int width = fontMetrics.size (0, QString::fromAscii ("This is a pretty long torrent filename indeed.torrent")).width (); 110 QLabel * l = new QLabel (tr ("&Torrent file:")); 111 layout->addWidget (l, row, 0, Qt::AlignLeft); 112 p = myFileButton = new QPushButton; 113 p->setIcon (filePixmap); 114 p->setMinimumWidth (width); 115 p->setStyleSheet (QString::fromAscii ("text-align: left; padding-left: 5; padding-right: 5")); 116 p->installEventFilter (this); 117 118 layout->addWidget (p, row, 1); 119 l->setBuddy (p); 120 connect (p, SIGNAL (clicked (bool)), this, SLOT (onFilenameClicked ())); 121 122 const QFileIconProvider iconProvider; 123 const QIcon folderIcon = iconProvider.icon (QFileIconProvider::Folder); 124 const QPixmap folderPixmap = folderIcon.pixmap (iconSize); 125 126 l = new QLabel (tr ("&Destination folder:")); 127 layout->addWidget (l, ++row, 0, Qt::AlignLeft); 128 const QString downloadDir (prefs.getString (Prefs::DOWNLOAD_DIR)); 129 myFreespaceLabel = new FreespaceLabel (mySession, downloadDir, this); 130 131 if (session.isLocal ()) 132 { 133 myDestination.setPath (downloadDir); 134 p = myDestinationButton = new QPushButton; 135 p->setIcon (folderPixmap); 136 p->setStyleSheet ("text-align: left; padding-left: 5; padding-right: 5"); 137 p->installEventFilter (this); 138 layout->addWidget (p, row, 1); 139 l->setBuddy (p); 140 connect (p, SIGNAL (clicked (bool)), this, SLOT (onDestinationClicked ())); 141 } 142 else 143 { 144 QLineEdit * e = myDestinationEdit = new QLineEdit; 145 e->setText (downloadDir); 146 layout->addWidget (e, row, 1); 147 l->setBuddy (e); 148 connect (e, SIGNAL (textEdited (const QString&)), this, SLOT (onDestinationEdited (const QString&))); 149 } 150 151 l = myFreespaceLabel; 152 layout->addWidget (l, ++row, 0, 1, 2, Qt::Alignment (Qt::AlignRight | Qt::AlignTop)); 153 layout->setRowMinimumHeight (row, l->height () + HIG::PAD_SMALL); 154 155 myTree = new FileTreeView (0, false); 156 layout->addWidget (myTree, ++row, 0, 1, 2); 157 if (!session.isLocal ()) 158 myTree->hideColumn (2); // hide the % done, since we've no way of knowing 159 160 QComboBox * m = new QComboBox; 161 m->addItem (tr ("High"), TR_PRI_HIGH); 162 m->addItem (tr ("Normal"), TR_PRI_NORMAL); 163 m->addItem (tr ("Low"), TR_PRI_LOW); 164 m->setCurrentIndex (1); // Normal 165 myPriorityCombo = m; 166 l = new QLabel (tr ("Torrent &priority:")); 167 l->setBuddy (m); 168 layout->addWidget (l, ++row, 0, Qt::AlignLeft); 169 layout->addWidget (m, row, 1); 170 171 if (session.isLocal ()) 172 { 173 p = myVerifyButton = new QPushButton (tr ("&Verify Local Data")); 174 layout->addWidget (p, ++row, 0, Qt::AlignLeft); 175 } 176 177 QCheckBox * c; 178 c = myStartCheck = new QCheckBox (tr ("&Start when added")); 179 c->setChecked (prefs.getBool (Prefs :: START)); 180 layout->addWidget (c, ++row, 0, 1, 2, Qt::AlignLeft); 181 182 c = myTrashCheck = new QCheckBox (tr ("Mo&ve .torrent file to the trash")); 183 c->setChecked (prefs.getBool (Prefs :: TRASH_ORIGINAL)); 184 layout->addWidget (c, ++row, 0, 1, 2, Qt::AlignLeft); 185 186 QDialogButtonBox * b = new QDialogButtonBox (QDialogButtonBox::Open|QDialogButtonBox::Cancel, Qt::Horizontal, this); 187 connect (b, SIGNAL (rejected ()), this, SLOT (deleteLater ())); 188 connect (b, SIGNAL (accepted ()), this, SLOT (onAccepted ())); 189 layout->addWidget (b, ++row, 0, 1, 2); 190 191 layout->setRowStretch (3, 2); 192 layout->setColumnStretch (1, 2); 193 layout->setSpacing (HIG :: PAD); 194 195 connect (myTree, SIGNAL (priorityChanged (const QSet<int>&,int)), this, SLOT (onPriorityChanged (const QSet<int>&,int))); 196 connect (myTree, SIGNAL (wantedChanged (const QSet<int>&,bool)), this, SLOT (onWantedChanged (const QSet<int>&,bool))); 197 if (session.isLocal ()) 198 connect (myVerifyButton, SIGNAL (clicked (bool)), this, SLOT (onVerify ())); 199 200 connect (&myVerifyTimer, SIGNAL (timeout ()), this, SLOT (onTimeout ())); 201 202 reload (); 203 } 204 205 Options :: ~Options () 206 { 207 clearInfo (); 204 208 } 205 209 … … 209 213 210 214 void 211 Options :: refreshButton( QPushButton * p, const QString& text, int width ) 212 { 213 if( width <= 0 ) width = p->width( ); 214 width -= 15; 215 QFontMetrics fontMetrics( font( ) ); 216 QString str = fontMetrics.elidedText( text, Qt::ElideRight, width ); 217 p->setText( str ); 218 } 219 220 void 221 Options :: refreshFileButton( int width ) 222 { 223 QString text; 224 225 switch( myAdd.type ) 226 { 227 case AddData::FILENAME: text = QFileInfo(myAdd.filename).completeBaseName(); break; 228 case AddData::URL: text = myAdd.url.toString(); break; 229 case AddData::MAGNET: text = myAdd.magnet; break; 230 default: break; 231 } 232 233 refreshButton( myFileButton, text, width ); 234 } 235 236 void 237 Options :: refreshDestinationButton( int width ) 238 { 239 if( myDestinationButton != 0 ) 240 refreshButton( myDestinationButton, myDestination.absolutePath(), width ); 215 Options :: refreshButton (QPushButton * p, const QString& text, int width) 216 { 217 if (width <= 0) 218 width = p->width (); 219 width -= 15; 220 QFontMetrics fontMetrics (font ()); 221 QString str = fontMetrics.elidedText (text, Qt::ElideRight, width); 222 p->setText (str); 223 } 224 225 void 226 Options :: refreshFileButton (int width) 227 { 228 QString text; 229 230 switch (myAdd.type) 231 { 232 case AddData::FILENAME: text = QFileInfo (myAdd.filename).completeBaseName (); break; 233 case AddData::URL: text = myAdd.url.toString (); break; 234 case AddData::MAGNET: text = myAdd.magnet; break; 235 default: break; 236 } 237 238 refreshButton (myFileButton, text, width); 239 } 240 241 void 242 Options :: refreshDestinationButton (int width) 243 { 244 if (myDestinationButton != 0) 245 refreshButton (myDestinationButton, myDestination.absolutePath (), width); 241 246 } 242 247 243 248 244 249 bool 245 Options :: eventFilter ( QObject * o, QEvent * event)246 { 247 if( o==myFileButton && event->type() == QEvent::Resize)248 { 249 refreshFileButton( dynamic_cast<QResizeEvent*>(event)->size().width());250 } 251 252 if( o==myDestinationButton && event->type() == QEvent::Resize)253 { 254 refreshDestinationButton( dynamic_cast<QResizeEvent*>(event)->size().width());255 } 256 257 250 Options :: eventFilter (QObject * o, QEvent * event) 251 { 252 if (o==myFileButton && event->type () == QEvent::Resize) 253 { 254 refreshFileButton (dynamic_cast<QResizeEvent*> (event)->size ().width ()); 255 } 256 257 if (o==myDestinationButton && event->type () == QEvent::Resize) 258 { 259 refreshDestinationButton (dynamic_cast<QResizeEvent*> (event)->size ().width ()); 260 } 261 262 return false; 258 263 } 259 264 … … 263 268 264 269 void 265 Options :: clearInfo( ) 266 { 267 if( myHaveInfo ) 268 tr_metainfoFree( &myInfo ); 269 myHaveInfo = false; 270 myFiles.clear( ); 271 } 272 273 void 274 Options :: reload( ) 275 { 276 clearInfo( ); 277 clearVerify( ); 278 279 tr_ctor * ctor = tr_ctorNew( 0 ); 280 281 switch( myAdd.type ) { 282 case AddData::MAGNET: tr_ctorSetMetainfoFromMagnetLink( ctor, myAdd.magnet.toUtf8().constData() ); break; 283 case AddData::FILENAME: tr_ctorSetMetainfoFromFile( ctor, myAdd.filename.toUtf8().constData() ); break; 284 case AddData::METAINFO: tr_ctorSetMetainfo( ctor, (const uint8_t*)myAdd.metainfo.constData(), myAdd.metainfo.size() ); break; 285 default: break; 286 } 287 288 const int err = tr_torrentParse( ctor, &myInfo ); 289 myHaveInfo = !err; 290 tr_ctorFree( ctor ); 291 292 myTree->clear( ); 293 myFiles.clear( ); 294 myPriorities.clear( ); 295 myWanted.clear( ); 296 297 if( myHaveInfo ) 298 { 299 myPriorities.insert( 0, myInfo.fileCount, TR_PRI_NORMAL ); 300 myWanted.insert( 0, myInfo.fileCount, true ); 301 302 for( tr_file_index_t i=0; i<myInfo.fileCount; ++i ) { 303 TrFile file; 304 file.index = i; 305 file.priority = myPriorities[i]; 306 file.wanted = myWanted[i]; 307 file.size = myInfo.files[i].length; 308 file.have = 0; 309 file.filename = QString::fromUtf8( myInfo.files[i].name ); 310 myFiles.append( file ); 270 Options :: clearInfo () 271 { 272 if (myHaveInfo) 273 tr_metainfoFree (&myInfo); 274 275 myHaveInfo = false; 276 myFiles.clear (); 277 } 278 279 void 280 Options :: reload () 281 { 282 clearInfo (); 283 clearVerify (); 284 285 tr_ctor * ctor = tr_ctorNew (0); 286 287 switch (myAdd.type) 288 { 289 case AddData::MAGNET: 290 tr_ctorSetMetainfoFromMagnetLink (ctor, myAdd.magnet.toUtf8 ().constData ()); 291 break; 292 293 case AddData::FILENAME: 294 tr_ctorSetMetainfoFromFile (ctor, myAdd.filename.toUtf8 ().constData ()); 295 break; 296 297 case AddData::METAINFO: 298 tr_ctorSetMetainfo (ctor, (const uint8_t*)myAdd.metainfo.constData (), myAdd.metainfo.size ()); 299 break; 300 301 default: 302 break; 303 } 304 305 const int err = tr_torrentParse (ctor, &myInfo); 306 myHaveInfo = !err; 307 tr_ctorFree (ctor); 308 309 myTree->clear (); 310 myFiles.clear (); 311 myPriorities.clear (); 312 myWanted.clear (); 313 314 if (myHaveInfo) 315 { 316 myPriorities.insert (0, myInfo.fileCount, TR_PRI_NORMAL); 317 myWanted.insert (0, myInfo.fileCount, true); 318 319 for (tr_file_index_t i=0; i<myInfo.fileCount; ++i) 320 { 321 TrFile file; 322 file.index = i; 323 file.priority = myPriorities[i]; 324 file.wanted = myWanted[i]; 325 file.size = myInfo.files[i].length; 326 file.have = 0; 327 file.filename = QString::fromUtf8 (myInfo.files[i].name); 328 myFiles.append (file); 311 329 } 312 330 } 313 331 314 myTree->update( myFiles ); 315 } 316 317 void 318 Options :: onPriorityChanged( const QSet<int>& fileIndices, int priority ) 319 { 320 foreach( int i, fileIndices ) 321 myPriorities[i] = priority; 322 } 323 324 void 325 Options :: onWantedChanged( const QSet<int>& fileIndices, bool isWanted ) 326 { 327 foreach( int i, fileIndices ) 328 myWanted[i] = isWanted; 329 } 330 331 void 332 Options :: onAccepted( ) 333 { 334 // rpc spec section 3.4 "adding a torrent" 335 336 const int64_t tag = mySession.getUniqueTag( ); 337 tr_variant top; 338 tr_variantInitDict (&top, 3); 339 tr_variantDictAddStr (&top, TR_KEY_method, "torrent-add" ); 340 tr_variantDictAddInt (&top, TR_KEY_tag, tag ); 341 tr_variant * args (tr_variantDictAddDict(&top, TR_KEY_arguments, 10)); 342 QString downloadDir; 343 344 // "download-dir" 345 if (myDestinationButton) 346 downloadDir = myDestination.absolutePath(); 347 else 348 downloadDir = myDestinationEdit->text(); 349 tr_variantDictAddStr (args, TR_KEY_download_dir, downloadDir.toUtf8().constData() ); 350 351 // "metainfo" 352 switch( myAdd.type ) 353 { 354 case AddData::MAGNET: 355 tr_variantDictAddStr (args, TR_KEY_filename, myAdd.magnet.toUtf8().constData()); 356 break; 357 358 case AddData::URL: 359 tr_variantDictAddStr (args, TR_KEY_filename, myAdd.url.toString().toUtf8().constData()); 360 break; 361 362 case AddData::FILENAME: 363 case AddData::METAINFO: { 364 const QByteArray b64 = myAdd.toBase64( ); 365 tr_variantDictAddRaw( args, TR_KEY_metainfo, b64.constData(), b64.size() ); 366 break; 367 } 368 369 default: 370 qWarning ("unhandled AddData.type: %d", myAdd.type); 371 } 372 373 // paused 374 tr_variantDictAddBool( args, TR_KEY_paused, !myStartCheck->isChecked( ) ); 375 376 // priority 377 const int index = myPriorityCombo->currentIndex( ); 378 const int priority = myPriorityCombo->itemData(index).toInt( ); 379 tr_variantDictAddInt( args, TR_KEY_bandwidthPriority, priority ); 380 381 // files-unwanted 382 int count = myWanted.count( false ); 383 if( count > 0 ) { 384 tr_variant * l = tr_variantDictAddList( args, TR_KEY_files_unwanted, count ); 385 for( int i=0, n=myWanted.size(); i<n; ++i ) 386 if( myWanted.at(i) == false ) 387 tr_variantListAddInt( l, i ); 388 } 389 390 // priority-low 391 count = myPriorities.count( TR_PRI_LOW ); 392 if( count > 0 ) { 393 tr_variant * l = tr_variantDictAddList( args, TR_KEY_priority_low, count ); 394 for( int i=0, n=myPriorities.size(); i<n; ++i ) 395 if( myPriorities.at(i) == TR_PRI_LOW ) 396 tr_variantListAddInt( l, i ); 397 } 398 399 // priority-high 400 count = myPriorities.count( TR_PRI_HIGH ); 401 if( count > 0 ) { 402 tr_variant * l = tr_variantDictAddList( args, TR_KEY_priority_high, count ); 403 for( int i=0, n=myPriorities.size(); i<n; ++i ) 404 if( myPriorities.at(i) == TR_PRI_HIGH ) 405 tr_variantListAddInt( l, i ); 406 } 407 408 // maybe delete the source .torrent 409 FileAdded * fileAdded = new FileAdded( tag, myAdd.readableName() ); 410 if( myTrashCheck->isChecked( ) && ( myAdd.type==AddData::FILENAME ) ) 411 fileAdded->setFileToDelete( myAdd.filename ); 412 connect( &mySession, SIGNAL(executed(int64_t,const QString&, struct tr_variant*)), 413 fileAdded, SLOT(executed(int64_t,const QString&, struct tr_variant*))); 414 415 mySession.exec( &top ); 416 417 tr_variantFree( &top ); 418 deleteLater( ); 419 } 420 421 void 422 Options :: onFilenameClicked( ) 423 { 424 if( myAdd.type == AddData::FILENAME ) 425 { 426 QFileDialog * d = new QFileDialog( this, 427 tr( "Open Torrent" ), 428 QFileInfo(myAdd.filename).absolutePath(), 429 tr( "Torrent Files (*.torrent);;All Files (*.*)" ) ); 430 d->setFileMode( QFileDialog::ExistingFile ); 431 d->setAttribute( Qt::WA_DeleteOnClose ); 432 connect( d, SIGNAL(filesSelected(const QStringList&)), this, SLOT(onFilesSelected(const QStringList&)) ); 433 d->show( ); 434 } 435 } 436 437 void 438 Options :: onFilesSelected( const QStringList& files ) 439 { 440 if( files.size() == 1 ) 441 { 442 myAdd.set( files.at(0) ); 443 refreshFileButton( ); 444 reload( ); 445 } 446 } 447 448 void 449 Options :: onDestinationClicked( ) 450 { 451 QFileDialog * d = new QFileDialog( this, 452 tr( "Select Destination" ), 453 myDestination.absolutePath( ) ); 454 d->setFileMode( QFileDialog::Directory ); 455 d->setAttribute( Qt::WA_DeleteOnClose ); 456 connect( d, SIGNAL(filesSelected(const QStringList&)), this, SLOT(onDestinationsSelected(const QStringList&)) ); 457 d->show( ); 332 myTree->update (myFiles); 333 } 334 335 void 336 Options :: onPriorityChanged (const QSet<int>& fileIndices, int priority) 337 { 338 foreach (int i, fileIndices) 339 myPriorities[i] = priority; 340 } 341 342 void 343 Options :: onWantedChanged (const QSet<int>& fileIndices, bool isWanted) 344 { 345 foreach (int i, fileIndices) 346 myWanted[i] = isWanted; 347 } 348 349 void 350 Options :: onAccepted () 351 { 352 // rpc spec section 3.4 "adding a torrent" 353 354 const int64_t tag = mySession.getUniqueTag (); 355 tr_variant top; 356 tr_variantInitDict (&top, 3); 357 tr_variantDictAddStr (&top, TR_KEY_method, "torrent-add"); 358 tr_variantDictAddInt (&top, TR_KEY_tag, tag); 359 tr_variant * args (tr_variantDictAddDict (&top, TR_KEY_arguments, 10)); 360 QString downloadDir; 361 362 // "download-dir" 363 if (myDestinationButton) 364 downloadDir = myDestination.absolutePath (); 365 else 366 downloadDir = myDestinationEdit->text (); 367 tr_variantDictAddStr (args, TR_KEY_download_dir, downloadDir.toUtf8 ().constData ()); 368 369 // "metainfo" 370 switch (myAdd.type) 371 { 372 case AddData::MAGNET: 373 tr_variantDictAddStr (args, TR_KEY_filename, myAdd.magnet.toUtf8 ().constData ()); 374 break; 375 376 case AddData::URL: 377 tr_variantDictAddStr (args, TR_KEY_filename, myAdd.url.toString ().toUtf8 ().constData ()); 378 break; 379 380 case AddData::FILENAME: 381 case AddData::METAINFO: { 382 const QByteArray b64 = myAdd.toBase64 (); 383 tr_variantDictAddRaw (args, TR_KEY_metainfo, b64.constData (), b64.size ()); 384 break; 385 } 386 387 default: 388 qWarning ("unhandled AddData.type: %d", myAdd.type); 389 } 390 391 // paused 392 tr_variantDictAddBool (args, TR_KEY_paused, !myStartCheck->isChecked ()); 393 394 // priority 395 const int index = myPriorityCombo->currentIndex (); 396 const int priority = myPriorityCombo->itemData (index).toInt (); 397 tr_variantDictAddInt (args, TR_KEY_bandwidthPriority, priority); 398 399 // files-unwanted 400 int count = myWanted.count (false); 401 if (count > 0) 402 { 403 tr_variant * l = tr_variantDictAddList (args, TR_KEY_files_unwanted, count); 404 for (int i=0, n=myWanted.size (); i<n; ++i) 405 if (myWanted.at (i) == false) 406 tr_variantListAddInt (l, i); 407 } 408 409 // priority-low 410 count = myPriorities.count (TR_PRI_LOW); 411 if (count > 0) 412 { 413 tr_variant * l = tr_variantDictAddList (args, TR_KEY_priority_low, count); 414 for (int i=0, n=myPriorities.size (); i<n; ++i) 415 if (myPriorities.at (i) == TR_PRI_LOW) 416 tr_variantListAddInt (l, i); 417 } 418 419 // priority-high 420 count = myPriorities.count (TR_PRI_HIGH); 421 if (count > 0) 422 { 423 tr_variant * l = tr_variantDictAddList (args, TR_KEY_priority_high, count); 424 for (int i=0, n=myPriorities.size (); i<n; ++i) 425 if (myPriorities.at (i) == TR_PRI_HIGH) 426 tr_variantListAddInt (l, i); 427 } 428 429 // maybe delete the source .torrent 430 FileAdded * fileAdded = new FileAdded (tag, myAdd.readableName ()); 431 if (myTrashCheck->isChecked () && (myAdd.type==AddData::FILENAME)) 432 fileAdded->setFileToDelete (myAdd.filename); 433 connect (&mySession, SIGNAL (executed (int64_t,const QString&, struct tr_variant*)), 434 fileAdded, SLOT (executed (int64_t,const QString&, struct tr_variant*))); 435 436 mySession.exec (&top); 437 438 tr_variantFree (&top); 439 deleteLater (); 440 } 441 442 void 443 Options :: onFilenameClicked () 444 { 445 if (myAdd.type == AddData::FILENAME) 446 { 447 QFileDialog * d = new QFileDialog (this, 448 tr ("Open Torrent"), 449 QFileInfo (myAdd.filename).absolutePath (), 450 tr ("Torrent Files (*.torrent);;All Files (*.*)")); 451 d->setFileMode (QFileDialog::ExistingFile); 452 d->setAttribute (Qt::WA_DeleteOnClose); 453 connect (d, SIGNAL (filesSelected (const QStringList&)), this, SLOT (onFilesSelected (const QStringList&))); 454 d->show (); 455 } 456 } 457 458 void 459 Options :: onFilesSelected (const QStringList& files) 460 { 461 if (files.size () == 1) 462 { 463 myAdd.set (files.at (0)); 464 refreshFileButton (); 465 reload (); 466 } 467 } 468 469 void 470 Options :: onDestinationClicked () 471 { 472 QFileDialog * d = new QFileDialog (this, tr ("Select Destination"), myDestination.absolutePath ()); 473 d->setFileMode (QFileDialog::Directory); 474 d->setAttribute (Qt::WA_DeleteOnClose); 475 connect (d, SIGNAL (filesSelected (const QStringList&)), this, SLOT (onDestinationsSelected (const QStringList&))); 476 d->show (); 458 477 } 459 478 … … 461 480 Options :: onDestinationsSelected (const QStringList& destinations) 462 481 { 463 if (destinations.size () == 1)482 if (destinations.size () == 1) 464 483 { 465 484 const QString& destination (destinations.first ()); … … 481 500 Options :: onDestinationEditedIdle () 482 501 { 483 myFreespaceLabel->setPath (myDestinationEdit->text ());502 myFreespaceLabel->setPath (myDestinationEdit->text ()); 484 503 } 485 504 … … 491 510 492 511 void 493 Options :: clearVerify( ) 494 { 495 myVerifyHash.reset( ); 496 myVerifyFile.close( ); 497 myVerifyFilePos = 0; 498 myVerifyFlags.clear( ); 499 myVerifyFileIndex = 0; 500 myVerifyPieceIndex = 0; 501 myVerifyPiecePos = 0; 502 myVerifyTimer.stop( ); 503 504 for( int i=0, n=myFiles.size(); i<n; ++i ) 505 myFiles[i].have = 0; 506 myTree->update( myFiles ); 507 } 508 509 void 510 Options :: onVerify( ) 511 { 512 clearVerify( ); 513 myVerifyFlags.insert( 0, myInfo.pieceCount, false ); 514 myVerifyTimer.setSingleShot( false ); 515 myVerifyTimer.start( 0 ); 512 Options :: clearVerify () 513 { 514 myVerifyHash.reset (); 515 myVerifyFile.close (); 516 myVerifyFilePos = 0; 517 myVerifyFlags.clear (); 518 myVerifyFileIndex = 0; 519 myVerifyPieceIndex = 0; 520 myVerifyPiecePos = 0; 521 myVerifyTimer.stop (); 522 523 for (int i=0, n=myFiles.size (); i<n; ++i) 524 myFiles[i].have = 0; 525 526 myTree->update (myFiles); 527 } 528 529 void 530 Options :: onVerify () 531 { 532 clearVerify (); 533 myVerifyFlags.insert (0, myInfo.pieceCount, false); 534 myVerifyTimer.setSingleShot (false); 535 myVerifyTimer.start (0); 516 536 } 517 537 518 538 namespace 519 539 { 520 uint64_t getPieceSize( const tr_info * info, tr_piece_index_t pieceIndex ) 521 { 522 if( pieceIndex != info->pieceCount - 1 ) 523 return info->pieceSize; 524 return info->totalSize % info->pieceSize; 525 } 526 } 527 528 void 529 Options :: onTimeout( ) 530 { 531 const tr_file * file = &myInfo.files[myVerifyFileIndex]; 532 533 if( !myVerifyFilePos && !myVerifyFile.isOpen( ) ) 534 { 535 const QFileInfo fileInfo( myDestination, QString::fromUtf8( file->name ) ); 536 myVerifyFile.setFileName( fileInfo.absoluteFilePath( ) ); 537 myVerifyFile.open( QIODevice::ReadOnly ); 538 } 539 540 int64_t leftInPiece = getPieceSize( &myInfo, myVerifyPieceIndex ) - myVerifyPiecePos; 541 int64_t leftInFile = file->length - myVerifyFilePos; 542 int64_t bytesThisPass = std::min( leftInFile, leftInPiece ); 543 bytesThisPass = std::min( bytesThisPass, (int64_t)sizeof( myVerifyBuf ) ); 544 545 if( myVerifyFile.isOpen() && myVerifyFile.seek( myVerifyFilePos ) ) { 546 int64_t numRead = myVerifyFile.read( myVerifyBuf, bytesThisPass ); 547 if( numRead == bytesThisPass ) 548 myVerifyHash.addData( myVerifyBuf, numRead ); 549 } 550 551 leftInPiece -= bytesThisPass; 552 leftInFile -= bytesThisPass; 553 myVerifyPiecePos += bytesThisPass; 554 myVerifyFilePos += bytesThisPass; 555 556 myVerifyBins[myVerifyFileIndex] += bytesThisPass; 557 558 if( leftInPiece == 0 ) 559 { 560 const QByteArray result( myVerifyHash.result( ) ); 561 const bool matches = !memcmp( result.constData(), 562 myInfo.pieces[myVerifyPieceIndex].hash, 563 SHA_DIGEST_LENGTH ); 564 myVerifyFlags[myVerifyPieceIndex] = matches; 565 myVerifyPiecePos = 0; 566 ++myVerifyPieceIndex; 567 myVerifyHash.reset( ); 568 569 FileList changedFiles; 570 if( matches ) { 571 mybins_t::const_iterator i; 572 for( i=myVerifyBins.begin(); i!=myVerifyBins.end(); ++i ) { 573 TrFile& f( myFiles[i.key( )] ); 574 f.have += i.value( ); 575 changedFiles.append( f ); 540 uint64_t getPieceSize (const tr_info * info, tr_piece_index_t pieceIndex) 541 { 542 if (pieceIndex != info->pieceCount - 1) 543 return info->pieceSize; 544 return info->totalSize % info->pieceSize; 545 } 546 } 547 548 void 549 Options :: onTimeout () 550 { 551 const tr_file * file = &myInfo.files[myVerifyFileIndex]; 552 553 if (!myVerifyFilePos && !myVerifyFile.isOpen ()) 554 { 555 const QFileInfo fileInfo (myDestination, QString::fromUtf8 (file->name)); 556 myVerifyFile.setFileName (fileInfo.absoluteFilePath ()); 557 myVerifyFile.open (QIODevice::ReadOnly); 558 } 559 560 int64_t leftInPiece = getPieceSize (&myInfo, myVerifyPieceIndex) - myVerifyPiecePos; 561 int64_t leftInFile = file->length - myVerifyFilePos; 562 int64_t bytesThisPass = std::min (leftInFile, leftInPiece); 563 bytesThisPass = std::min (bytesThisPass, (int64_t)sizeof (myVerifyBuf)); 564 565 if (myVerifyFile.isOpen () && myVerifyFile.seek (myVerifyFilePos)) 566 { 567 int64_t numRead = myVerifyFile.read (myVerifyBuf, bytesThisPass); 568 if (numRead == bytesThisPass) 569 myVerifyHash.addData (myVerifyBuf, numRead); 570 } 571 572 leftInPiece -= bytesThisPass; 573 leftInFile -= bytesThisPass; 574 myVerifyPiecePos += bytesThisPass; 575 myVerifyFilePos += bytesThisPass; 576 577 myVerifyBins[myVerifyFileIndex] += bytesThisPass; 578 579 if (leftInPiece == 0) 580 { 581 const QByteArray result (myVerifyHash.result ()); 582 const bool matches = !memcmp (result.constData (), 583 myInfo.pieces[myVerifyPieceIndex].hash, 584 SHA_DIGEST_LENGTH); 585 myVerifyFlags[myVerifyPieceIndex] = matches; 586 myVerifyPiecePos = 0; 587 ++myVerifyPieceIndex; 588 myVerifyHash.reset (); 589 590 FileList changedFiles; 591 if (matches) 592 { 593 mybins_t::const_iterator i; 594 for (i=myVerifyBins.begin (); i!=myVerifyBins.end (); ++i) 595 { 596 TrFile& f (myFiles[i.key ()]); 597 f.have += i.value (); 598 changedFiles.append (f); 576 599 } 577 600 } 578 myTree->update( changedFiles);579 myVerifyBins.clear();580 } 581 582 if( leftInFile == 0)583 { 584 myVerifyFile.close();585 586 587 } 588 589 590 if( done)591 { 592 593 foreach( const TrFile& f, myFiles)594 595 596 if( !have) // everything failed601 myTree->update (changedFiles); 602 myVerifyBins.clear (); 603 } 604 605 if (leftInFile == 0) 606 { 607 myVerifyFile.close (); 608 ++myVerifyFileIndex; 609 myVerifyFilePos = 0; 610 } 611 612 bool done = myVerifyPieceIndex >= myInfo.pieceCount; 613 if (done) 614 { 615 uint64_t have = 0; 616 foreach (const TrFile& f, myFiles) 617 have += f.have; 618 619 if (!have) // everything failed 597 620 { 598 599 const QStringList tokens = QString(file->name).split('/');600 if( !tokens.empty() && myDestination.dirName()==tokens.at(0))621 // did the user accidentally specify the child directory instead of the parent? 622 const QStringList tokens = QString (file->name).split ('/'); 623 if (!tokens.empty () && myDestination.dirName ()==tokens.at (0)) 601 624 { 602 603 myDestination.cdUp();604 refreshDestinationButton( -1);605 onVerify();606 625 // move up one directory and try again 626 myDestination.cdUp (); 627 refreshDestinationButton (-1); 628 onVerify (); 629 done = false; 607 630 } 608 631 } 609 632 } 610 633 611 if( done)612 myVerifyTimer.stop();613 } 634 if (done) 635 myVerifyTimer.stop (); 636 } -
trunk/qt/options.h
r13992 r14001 45 45 class FileAdded: public QObject 46 46 { 47 Q_OBJECT 48 const int64_t myTag; 49 QString myName; 50 QString myDelFile; 47 Q_OBJECT 51 48 52 53 FileAdded( int tag, const QString& name ): myTag(tag), myName(name) { }54 ~FileAdded() { }55 void setFileToDelete( const QString& file) { myDelFile = file; }49 public: 50 FileAdded (int tag, const QString& name): myTag (tag), myName (name) { } 51 ~FileAdded () { } 52 void setFileToDelete (const QString& file) { myDelFile = file; } 56 53 57 public slots: 58 void executed( int64_t tag, const QString& result, struct tr_variant * arguments ); 54 public slots: 55 void executed (int64_t tag, const QString& result, struct tr_variant * arguments); 56 57 private: 58 const int64_t myTag; 59 QString myName; 60 QString myDelFile; 59 61 }; 60 62 61 63 class Options: public QDialog 62 64 { 63 65 Q_OBJECT 64 66 65 66 Options( Session& session, const Prefs& prefs, const AddData& addme, QWidget * parent = 0);67 ~Options();67 public: 68 Options (Session& session, const Prefs& prefs, const AddData& addme, QWidget * parent = 0); 69 ~Options (); 68 70 69 private: 70 void reload( ); 71 void clearInfo( ); 72 void refreshFileButton( int width=-1 ); 73 void refreshDestinationButton( int width=-1 ); 74 void refreshButton( QPushButton *, const QString&, int width=-1 ); 71 private: 72 void reload (); 73 void clearInfo (); 74 void refreshFileButton (int width=-1); 75 void refreshDestinationButton (int width=-1); 76 void refreshButton (QPushButton *, const QString&, int width=-1); 77 bool eventFilter (QObject *, QEvent *); 75 78 76 private: 77 Session& mySession; 78 AddData myAdd; 79 QDir myDestination; 80 bool myHaveInfo; 81 tr_info myInfo; 82 FileTreeView * myTree; 83 FreespaceLabel * myFreespaceLabel; 84 QCheckBox * myStartCheck; 85 QCheckBox * myTrashCheck; 86 QComboBox * myPriorityCombo; 87 QPushButton * myFileButton; 88 QPushButton * myDestinationButton; 89 QLineEdit * myDestinationEdit; 90 QPushButton * myVerifyButton; 91 QVector<int> myPriorities; 92 QVector<bool> myWanted; 93 FileList myFiles; 79 private slots: 80 void onAccepted (); 81 void onPriorityChanged (const QSet<int>& fileIndices, int); 82 void onWantedChanged (const QSet<int>& fileIndices, bool); 83 void onVerify (); 84 void onTimeout (); 85 void onFilenameClicked (); 86 void onDestinationClicked (); 87 void onFilesSelected (const QStringList&); 88 void onDestinationsSelected (const QStringList&); 89 void onDestinationEdited (const QString&); 90 void onDestinationEditedIdle (); 94 91 95 private slots: 96 void onAccepted( ); 97 void onPriorityChanged( const QSet<int>& fileIndices, int ); 98 void onWantedChanged( const QSet<int>& fileIndices, bool ); 99 void onVerify( ); 100 void onTimeout( ); 101 void onFilenameClicked( ); 102 void onDestinationClicked( ); 103 void onFilesSelected( const QStringList& ); 104 void onDestinationsSelected( const QStringList& ); 105 void onDestinationEdited (const QString&); 106 void onDestinationEditedIdle (); 92 private: 93 Session& mySession; 94 AddData myAdd; 95 QDir myDestination; 96 bool myHaveInfo; 97 tr_info myInfo; 98 FileTreeView * myTree; 99 FreespaceLabel * myFreespaceLabel; 100 QCheckBox * myStartCheck; 101 QCheckBox * myTrashCheck; 102 QComboBox * myPriorityCombo; 103 QPushButton * myFileButton; 104 QPushButton * myDestinationButton; 105 QLineEdit * myDestinationEdit; 106 QPushButton * myVerifyButton; 107 QVector<int> myPriorities; 108 QVector<bool> myWanted; 109 FileList myFiles; 107 110 108 private: 109 bool eventFilter( QObject *, QEvent * ); 110 111 private: 112 QTimer myVerifyTimer; 113 char myVerifyBuf[2048*4]; 114 QFile myVerifyFile; 115 uint64_t myVerifyFilePos; 116 int myVerifyFileIndex; 117 uint32_t myVerifyPieceIndex; 118 uint32_t myVerifyPiecePos; 119 void clearVerify( ); 120 QVector<bool> myVerifyFlags; 121 QCryptographicHash myVerifyHash; 122 typedef QMap<uint32_t,int32_t> mybins_t; 123 mybins_t myVerifyBins; 124 QTimer myEditTimer; 125 111 private: 112 QTimer myVerifyTimer; 113 char myVerifyBuf[2048*4]; 114 QFile myVerifyFile; 115 uint64_t myVerifyFilePos; 116 int myVerifyFileIndex; 117 uint32_t myVerifyPieceIndex; 118 uint32_t myVerifyPiecePos; 119 void clearVerify (); 120 QVector<bool> myVerifyFlags; 121 QCryptographicHash myVerifyHash; 122 typedef QMap<uint32_t,int32_t> mybins_t; 123 mybins_t myVerifyBins; 124 QTimer myEditTimer; 126 125 }; 127 126
Note: See TracChangeset
for help on using the changeset viewer.