2 * This file Copyright (C) Mnemosyne LLC
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10 * $Id: make-dialog.cc 11098 2010-08-02 20:55:11Z charles $
17 #include <QDialogButtonBox>
18 #include <QFileDialog>
19 #include <QFileIconProvider>
20 #include <QHBoxLayout>
24 #include <QPlainTextEdit>
25 #include <QProgressBar>
26 #include <QPushButton>
27 #include <QRadioButton>
31 #include <QVBoxLayout>
33 #include <libtransmission/transmission.h>
34 #include <libtransmission/makemeta.h>
35 #include <libtransmission/utils.h>
37 #include "formatter.h"
39 #include "make-dialog.h"
47 MakeDialog :: onNewDialogDestroyed( QObject
* o
)
55 MakeDialog :: onNewButtonBoxClicked( QAbstractButton
* button
)
57 switch( myNewButtonBox
->standardButton( button
) )
59 case QDialogButtonBox::Open
:
60 std::cerr
<< "calling mySession.addTorrent( " << qPrintable(myTarget
) << ", " << qPrintable(QFileInfo(myBuilder
->top
).dir().path()) << ')' << std::endl
;
61 mySession
.addNewlyCreatedTorrent( myTarget
, QFileInfo(myBuilder
->top
).dir().path() );
63 case QDialogButtonBox::Abort
:
64 myBuilder
->abortFlag
= true;
66 default: // QDialogButtonBox::Ok:
70 myNewDialog
->deleteLater( );
74 MakeDialog :: onProgress( )
77 const tr_metainfo_builder
* b
= myBuilder
;
78 const double denom
= b
->pieceCount
? b
->pieceCount
: 1;
79 myNewProgress
->setValue( (int) ((100.0 * b
->pieceIndex
) / denom
) );
82 const QString
base( QFileInfo(b
->top
).baseName() );
85 str
= tr( "Creating \"%1\"" ).arg( base
);
86 else if( b
->result
== TR_MAKEMETA_OK
)
87 str
= tr( "Created \"%1\"!" ).arg( base
);
88 else if( b
->result
== TR_MAKEMETA_URL
)
89 str
= tr( "Error: invalid announce URL \"%1\"" ).arg( b
->errfile
);
90 else if( b
->result
== TR_MAKEMETA_CANCELLED
)
91 str
= tr( "Cancelled" );
92 else if( b
->result
== TR_MAKEMETA_IO_READ
)
93 str
= tr( "Error reading \"%1\": %2" ).arg( b
->errfile
).arg( strerror(b
->my_errno
) );
94 else if( b
->result
== TR_MAKEMETA_IO_WRITE
)
95 str
= tr( "Error writing \"%1\": %2" ).arg( b
->errfile
).arg( strerror(b
->my_errno
) );
96 myNewLabel
->setText( str
);
99 (myNewButtonBox
->button(QDialogButtonBox::Abort
))->setEnabled( !b
->isDone
);
100 (myNewButtonBox
->button(QDialogButtonBox::Ok
))->setEnabled( b
->isDone
);
101 (myNewButtonBox
->button(QDialogButtonBox::Open
))->setEnabled( b
->isDone
&& !b
->result
);
106 MakeDialog :: makeTorrent( )
113 QList
<tr_tracker_info
> trackers
;
114 foreach( QString line
, myTrackerEdit
->toPlainText().split("\n") ) {
115 line
= line
.trimmed( );
116 if( line
.isEmpty( ) )
120 tmp
.announce
= tr_strdup( line
.toUtf8().constData( ) );
122 trackers
.append( tmp
);
127 QDialog
* dialog
= new QDialog( this );
128 dialog
->setWindowTitle( tr( "New Torrent" ) );
129 myNewDialog
= dialog
;
130 QVBoxLayout
* top
= new QVBoxLayout( dialog
);
131 top
->addWidget(( myNewLabel
= new QLabel
));
132 top
->addWidget(( myNewProgress
= new QProgressBar
));
133 QDialogButtonBox
* buttons
= new QDialogButtonBox( QDialogButtonBox::Ok
134 | QDialogButtonBox::Open
135 | QDialogButtonBox::Abort
);
136 myNewButtonBox
= buttons
;
137 connect( buttons
, SIGNAL(clicked(QAbstractButton
*)),
138 this, SLOT(onNewButtonBoxClicked(QAbstractButton
*)) );
139 top
->addWidget( buttons
);
142 connect( dialog
, SIGNAL(destroyed(QObject
*)),
143 this, SLOT(onNewDialogDestroyed(QObject
*)) );
144 myTimer
.start( 100 );
146 // the file to create
147 myTarget
= QDir( myDestination
).filePath( QFileInfo(myBuilder
->top
).baseName() + ".torrent" );
148 std::cerr
<< qPrintable(myTarget
) << std::endl
;
152 if( myCommentCheck
->isChecked() )
153 comment
= myCommentEdit
->text().toUtf8().constData();
155 // start making the torrent
156 tr_makeMetaInfo( myBuilder
,
157 myTarget
.toUtf8().constData(),
158 (trackers
.isEmpty() ? 0 : &trackers
.front()),
160 (comment
.isEmpty() ? NULL
: comment
.toUtf8().constData()),
161 myPrivateCheck
->isChecked() );
169 MakeDialog :: onFileClicked( )
171 QFileDialog
* d
= new QFileDialog( this, tr( "Select File" ) );
172 d
->setFileMode( QFileDialog::ExistingFile
);
173 connect( d
, SIGNAL(filesSelected(const QStringList
&)),
174 this, SLOT(onFileSelected(const QStringList
&)) );
178 MakeDialog :: onFileSelected( const QStringList
& list
)
181 onFileSelected( list
.front( ) );
184 MakeDialog :: onFileSelected( const QString
& filename
)
187 myFileButton
->setText( QFileInfo(myFile
).fileName() );
192 MakeDialog :: onFolderClicked( )
194 QFileDialog
* d
= new QFileDialog( this, tr( "Select Folder" ) );
195 d
->setFileMode( QFileDialog::Directory
);
196 connect( d
, SIGNAL(filesSelected(const QStringList
&)),
197 this, SLOT(onFolderSelected(const QStringList
&)) );
201 MakeDialog :: onFolderSelected( const QStringList
& list
)
204 onFolderSelected( list
.front( ) );
207 MakeDialog :: onFolderSelected( const QString
& filename
)
210 myFolderButton
->setText( QFileInfo(myFolder
).fileName() );
215 MakeDialog :: onDestinationClicked( )
217 QFileDialog
* d
= new QFileDialog( this, tr( "Select Folder" ) );
218 d
->setFileMode( QFileDialog::Directory
);
219 connect( d
, SIGNAL(filesSelected(const QStringList
&)),
220 this, SLOT(onDestinationSelected(const QStringList
&)) );
224 MakeDialog :: onDestinationSelected( const QStringList
& list
)
227 onDestinationSelected( list
.front() );
230 MakeDialog :: onDestinationSelected( const QString
& filename
)
232 myDestination
= filename
;
233 myDestinationButton
->setText( QFileInfo(myDestination
).fileName() );
237 MakeDialog :: enableBuddyWhenChecked( QRadioButton
* box
, QWidget
* buddy
)
239 connect( box
, SIGNAL(toggled(bool)), buddy
, SLOT(setEnabled(bool)) );
240 buddy
->setEnabled( box
->isChecked( ) );
243 MakeDialog :: enableBuddyWhenChecked( QCheckBox
* box
, QWidget
* buddy
)
245 connect( box
, SIGNAL(toggled(bool)), buddy
, SLOT(setEnabled(bool)) );
246 buddy
->setEnabled( box
->isChecked( ) );
250 MakeDialog :: getSource( ) const
252 return myFileRadio
->isChecked( ) ? myFile
: myFolder
;
256 MakeDialog :: onButtonBoxClicked( QAbstractButton
* button
)
258 switch( myButtonBox
->standardButton( button
) )
260 case QDialogButtonBox::Ok
:
264 default: // QDialogButtonBox::Close:
275 MakeDialog :: onSourceChanged( )
279 tr_metaInfoBuilderFree( myBuilder
);
283 const QString filename
= getSource( );
284 if( !filename
.isEmpty( ) )
285 myBuilder
= tr_metaInfoBuilderCreate( filename
.toUtf8().constData() );
289 text
= tr( "<i>No source selected<i>" );
291 QString files
= tr( "%Ln File(s)", 0, myBuilder
->fileCount
);
292 QString pieces
= tr( "%Ln Piece(s)", 0, myBuilder
->pieceCount
);
293 text
= tr( "%1 in %2; %3 @ %4" )
294 .arg( Formatter::sizeToString( myBuilder
->totalSize
) )
297 .arg( Formatter::sizeToString( myBuilder
->pieceSize
) );
300 mySourceLabel
->setText( text
);
304 // bah, there doesn't seem to be any cleaner way to override
305 // QPlainTextEdit's default desire to be 12 lines tall
306 class ShortPlainTextEdit
: public QPlainTextEdit
{
308 virtual ~ShortPlainTextEdit( ) { }
309 ShortPlainTextEdit( QWidget
* parent
= 0 ): QPlainTextEdit(parent
) { }
310 virtual QSize
sizeHint ( ) const { return QSize( 256, 50 ); }
313 MakeDialog :: MakeDialog( Session
& session
, QWidget
* parent
):
314 QDialog( parent
, Qt::Dialog
),
315 mySession( session
),
318 setAcceptDrops( true );
320 connect( &myTimer
, SIGNAL(timeout()), this, SLOT(onProgress()) );
322 setWindowTitle( tr( "New Torrent" ) );
323 QVBoxLayout
* top
= new QVBoxLayout( this );
324 top
->setSpacing( HIG :: PAD
);
327 hig
->setContentsMargins( 0, 0, 0, 0 );
328 hig
->addSectionTitle( tr( "Files" ) );
330 QFileIconProvider iconProvider
;
331 const int iconSize( style()->pixelMetric( QStyle::PM_SmallIconSize
) );
332 const QIcon folderIcon
= iconProvider
.icon( QFileIconProvider::Folder
);
333 const QPixmap folderPixmap
= folderIcon
.pixmap( iconSize
);
334 QPushButton
* b
= new QPushButton
;
335 b
->setIcon( folderPixmap
);
336 b
->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" );
337 myDestination
= QDir::homePath();
338 b
->setText( myDestination
);
339 connect( b
, SIGNAL(clicked(bool)),
340 this, SLOT(onDestinationClicked(void)) );
341 myDestinationButton
= b
;
342 hig
->addRow( tr( "Sa&ve to:" ), b
);
344 myFolderRadio
= new QRadioButton( tr( "Source F&older:" ) );
345 connect( myFolderRadio
, SIGNAL(toggled(bool)),
346 this, SLOT(onSourceChanged()) );
347 myFolderButton
= new QPushButton
;
348 myFolderButton
->setIcon( folderPixmap
);
349 myFolderButton
->setText( tr( "(None)" ) );
350 myFolderButton
->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" );
351 connect( myFolderButton
, SIGNAL(clicked(bool)),
352 this, SLOT(onFolderClicked(void)) );
353 hig
->addRow( myFolderRadio
, myFolderButton
);
354 enableBuddyWhenChecked( myFolderRadio
, myFolderButton
);
356 const QIcon fileIcon
= iconProvider
.icon( QFileIconProvider::File
);
357 const QPixmap filePixmap
= fileIcon
.pixmap( iconSize
);
358 myFileRadio
= new QRadioButton( tr( "Source &File:" ) );
359 myFileRadio
->setChecked( true );
360 connect( myFileRadio
, SIGNAL(toggled(bool)),
361 this, SLOT(onSourceChanged()) );
362 myFileButton
= new QPushButton
;
363 myFileButton
->setText( tr( "(None)" ) );
364 myFileButton
->setIcon( filePixmap
);
365 myFileButton
->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" );
366 connect( myFileButton
, SIGNAL(clicked(bool)),
367 this, SLOT(onFileClicked(void)) );
368 hig
->addRow( myFileRadio
, myFileButton
);
369 enableBuddyWhenChecked( myFileRadio
, myFileButton
);
371 mySourceLabel
= new QLabel( this );
372 hig
->addRow( tr( "" ), mySourceLabel
);
374 hig
->addSectionDivider( );
375 hig
->addSectionTitle( tr( "Properties" ) );
377 hig
->addWideControl( myTrackerEdit
= new ShortPlainTextEdit
);
378 const int height
= fontMetrics().size( 0, "\n\n\n\n" ).height( );
379 myTrackerEdit
->setMinimumHeight( height
);
380 hig
->addTallRow( tr( "&Trackers:" ), myTrackerEdit
);
381 QLabel
* l
= new QLabel( tr( "To add a backup URL, add it on the line after the primary URL.\nTo add another primary URL, add it after a blank line." ) );
382 l
->setAlignment( Qt::AlignLeft
);
383 hig
->addRow( tr( "" ), l
);
384 myTrackerEdit
->resize( 500, height
);
386 myCommentCheck
= new QCheckBox( tr( "Co&mment" ) );
387 myCommentEdit
= new QLineEdit( );
388 hig
->addRow( myCommentCheck
, myCommentEdit
);
389 enableBuddyWhenChecked( myCommentCheck
, myCommentEdit
);
391 myPrivateCheck
= hig
->addWideCheckBox( tr( "&Private torrent" ), false );
394 top
->addWidget( hig
, 1 );
396 myButtonBox
= new QDialogButtonBox( QDialogButtonBox::Ok
397 | QDialogButtonBox::Close
);
398 connect( myButtonBox
, SIGNAL(clicked(QAbstractButton
*)),
399 this, SLOT(onButtonBoxClicked(QAbstractButton
*)) );
401 top
->addWidget( myButtonBox
);
405 MakeDialog :: ~MakeDialog( )
408 tr_metaInfoBuilderFree( myBuilder
);
416 MakeDialog :: dragEnterEvent( QDragEnterEvent
* event
)
418 const QMimeData
* mime
= event
->mimeData( );
420 if( mime
->urls().size() && QFile(mime
->urls().front().path()).exists( ) )
421 event
->acceptProposedAction();
425 MakeDialog :: dropEvent( QDropEvent
* event
)
427 const QString filename
= event
->mimeData()->urls().front().path();
428 const QFileInfo
fileInfo( filename
);
430 if( fileInfo
.exists( ) )
432 if( fileInfo
.isDir( ) )
434 myFolderRadio
->setChecked( true );
435 onFolderSelected( filename
);
439 myFileRadio
->setChecked( true );
440 onFileSelected( filename
);