source: trunk/qt/make-dialog.cc @ 14179

Last change on this file since 14179 was 14179, checked in by jordan, 8 years ago

remove another spurious console message

  • Property svn:keywords set to Date Rev Author Id
File size: 13.9 KB
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
7 *
8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
9 *
10 * $Id: make-dialog.cc 14179 2013-08-24 20:22:38Z jordan $
11 */
12
13#include <cassert>
14#include <iostream>
15
16#include <QCheckBox>
17#include <QDialogButtonBox>
18#include <QFileDialog>
19#include <QFileIconProvider>
20#include <QHBoxLayout>
21#include <QLabel>
22#include <QLineEdit>
23#include <QList>
24#include <QMimeData>
25#include <QPlainTextEdit>
26#include <QProgressBar>
27#include <QPushButton>
28#include <QRadioButton>
29#include <QSize>
30#include <QStyle>
31#include <QTimer>
32#include <QVBoxLayout>
33
34#include <libtransmission/transmission.h>
35#include <libtransmission/makemeta.h>
36#include <libtransmission/utils.h>
37
38#include "formatter.h"
39#include "hig.h"
40#include "make-dialog.h"
41#include "session.h"
42
43/***
44****
45***/
46
47void
48MakeDialog :: onNewDialogDestroyed( QObject * o )
49{
50    Q_UNUSED( o );
51
52    myTimer.stop( );
53}
54
55void
56MakeDialog :: onNewButtonBoxClicked( QAbstractButton * button )
57{
58    switch( myNewButtonBox->standardButton( button ) )
59    {
60        case QDialogButtonBox::Open:
61            mySession.addNewlyCreatedTorrent( myTarget, QFileInfo(QString::fromUtf8(myBuilder->top)).dir().path() );
62            break;
63        case QDialogButtonBox::Abort:
64            myBuilder->abortFlag = true;
65            break;
66        default: // QDialogButtonBox::Ok:
67            break;
68
69    }
70    myNewDialog->deleteLater( );
71}
72
73void
74MakeDialog :: onProgress( )
75{
76    // progress bar
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 ) );
80
81    // progress label
82    const QString top = QString::fromLocal8Bit( myBuilder->top );
83    const QString base( QFileInfo(top).completeBaseName() );
84    QString str;
85    if( !b->isDone )
86        str = tr( "Creating \"%1\"" ).arg( base );
87    else if( b->result == TR_MAKEMETA_OK )
88        str = tr( "Created \"%1\"!" ).arg( base );
89    else if( b->result == TR_MAKEMETA_URL )
90        str = tr( "Error: invalid announce URL \"%1\"" ).arg( QString::fromLocal8Bit( b->errfile ) );
91    else if( b->result == TR_MAKEMETA_CANCELLED )
92        str = tr( "Cancelled" );
93    else if( b->result == TR_MAKEMETA_IO_READ )
94        str = tr( "Error reading \"%1\": %2" ).arg( QString::fromLocal8Bit(b->errfile) ).arg( QString::fromLocal8Bit(strerror(b->my_errno)) );
95    else if( b->result == TR_MAKEMETA_IO_WRITE )
96        str = tr( "Error writing \"%1\": %2" ).arg( QString::fromLocal8Bit(b->errfile) ).arg( QString::fromLocal8Bit(strerror(b->my_errno)) );
97    myNewLabel->setText( str );
98
99    // buttons
100    (myNewButtonBox->button(QDialogButtonBox::Abort))->setEnabled( !b->isDone );
101    (myNewButtonBox->button(QDialogButtonBox::Ok))->setEnabled( b->isDone );
102    (myNewButtonBox->button(QDialogButtonBox::Open))->setEnabled( b->isDone && !b->result );
103}
104
105
106void
107MakeDialog :: makeTorrent( )
108{
109    if( !myBuilder )
110        return;
111
112    // get the tiers
113    int tier = 0;
114    QVector<tr_tracker_info> trackers;
115    foreach( QString line, myTrackerEdit->toPlainText().split("\n") ) {
116        line = line.trimmed( );
117        if( line.isEmpty( ) )
118            ++tier;
119        else {
120            tr_tracker_info tmp;
121            tmp.announce = tr_strdup( line.toUtf8().constData( ) );
122            tmp.tier = tier;
123            trackers.append( tmp );
124        }
125    }
126
127    // pop up the dialog
128    QDialog * dialog = new QDialog( this );
129    dialog->setWindowTitle( tr( "New Torrent" ) );
130    myNewDialog = dialog;
131    QVBoxLayout * top = new QVBoxLayout( dialog );
132    top->addWidget(( myNewLabel = new QLabel));
133    top->addWidget(( myNewProgress = new QProgressBar ));
134    QDialogButtonBox * buttons = new QDialogButtonBox( QDialogButtonBox::Ok
135                                                     | QDialogButtonBox::Open
136                                                     | QDialogButtonBox::Abort );
137    myNewButtonBox = buttons;
138    connect( buttons, SIGNAL(clicked(QAbstractButton*)),
139             this, SLOT(onNewButtonBoxClicked(QAbstractButton*)) );
140    top->addWidget( buttons );
141    onProgress( );
142    dialog->show( );
143    connect( dialog, SIGNAL(destroyed(QObject*)),
144             this, SLOT(onNewDialogDestroyed(QObject*)) );
145    myTimer.start( 100 );
146
147    // the file to create
148    const QString path = QString::fromUtf8( myBuilder->top );
149    const QString torrentName = QFileInfo(path).completeBaseName() + ".torrent";
150    myTarget = QDir( myDestination ).filePath( torrentName );
151
152    // comment
153    QString comment;
154    if( myCommentCheck->isChecked() )
155        comment = myCommentEdit->text();
156
157    // start making the torrent
158    tr_makeMetaInfo( myBuilder,
159                     myTarget.toUtf8().constData(),
160                     (trackers.isEmpty() ? NULL : trackers.data()),
161                     trackers.size(),
162                     (comment.isEmpty() ? NULL : comment.toUtf8().constData()),
163                     myPrivateCheck->isChecked() );
164}
165
166/***
167****
168***/
169
170void
171MakeDialog :: onFileClicked( )
172{
173    QFileDialog * d = new QFileDialog( this, tr( "Select File" ) );
174    d->setFileMode( QFileDialog::ExistingFile );
175    d->setAttribute( Qt::WA_DeleteOnClose );
176    connect( d, SIGNAL(filesSelected(const QStringList&)),
177             this, SLOT(onFileSelected(const QStringList&)) );
178    d->show( );
179}
180void
181MakeDialog :: onFileSelected( const QStringList& list )
182{
183    if( !list.empty( ) )
184        onFileSelected( list.front( ) );
185}
186void
187MakeDialog :: onFileSelected( const QString& filename )
188{
189    myFile = filename;
190    myFileButton->setText( QFileInfo(myFile).fileName() );
191    onSourceChanged( );
192}
193
194void
195MakeDialog :: onFolderClicked( )
196{
197    QFileDialog * d = new QFileDialog( this, tr( "Select Folder" ) );
198    d->setFileMode( QFileDialog::Directory );
199    d->setOption( QFileDialog::ShowDirsOnly );
200    d->setAttribute( Qt::WA_DeleteOnClose );
201    connect( d, SIGNAL(filesSelected(const QStringList&)),
202             this, SLOT(onFolderSelected(const QStringList&)) );
203    d->show( );
204}
205void
206MakeDialog :: onFolderSelected( const QStringList& list )
207{
208    if( !list.empty( ) )
209        onFolderSelected( list.front( ) );
210}
211void
212MakeDialog :: onFolderSelected( const QString& filename )
213{
214    myFolder = filename;
215    myFolderButton->setText( QFileInfo(myFolder).fileName() );
216    onSourceChanged( );
217}
218
219void
220MakeDialog :: onDestinationClicked( )
221{
222    QFileDialog * d = new QFileDialog( this, tr( "Select Folder" ) );
223    d->setFileMode( QFileDialog::Directory );
224    d->setOption( QFileDialog::ShowDirsOnly );
225    d->setAttribute( Qt::WA_DeleteOnClose );
226    connect( d, SIGNAL(filesSelected(const QStringList&)),
227             this, SLOT(onDestinationSelected(const QStringList&)) );
228    d->show( );
229}
230void
231MakeDialog :: onDestinationSelected( const QStringList& list )
232{
233    if( !list.empty( ) )
234        onDestinationSelected( list.front() );
235}
236void
237MakeDialog :: onDestinationSelected( const QString& filename )
238{
239    myDestination = filename;
240    myDestinationButton->setText( QFileInfo(myDestination).fileName() );
241}
242
243void
244MakeDialog :: enableBuddyWhenChecked( QRadioButton * box, QWidget * buddy )
245{
246    connect( box, SIGNAL(toggled(bool)), buddy, SLOT(setEnabled(bool)) );
247    buddy->setEnabled( box->isChecked( ) );
248}
249void
250MakeDialog :: enableBuddyWhenChecked( QCheckBox * box, QWidget * buddy )
251{
252    connect( box, SIGNAL(toggled(bool)), buddy, SLOT(setEnabled(bool)) );
253    buddy->setEnabled( box->isChecked( ) );
254}
255
256QString
257MakeDialog :: getSource( ) const
258{
259    return myFileRadio->isChecked( ) ? myFile : myFolder;
260}
261
262void
263MakeDialog :: onButtonBoxClicked( QAbstractButton * button )
264{
265    switch( myButtonBox->standardButton( button ) )
266    {
267        case QDialogButtonBox::Ok:
268            makeTorrent( );
269            break;
270
271        default: // QDialogButtonBox::Close:
272            deleteLater( );
273            break;
274    }
275}
276
277/***
278****
279***/
280
281void
282MakeDialog :: onSourceChanged( )
283{
284    if( myBuilder )
285    {
286        tr_metaInfoBuilderFree( myBuilder );
287        myBuilder = 0;
288    }
289
290    const QString filename = getSource( );
291    if( !filename.isEmpty( ) )
292        myBuilder = tr_metaInfoBuilderCreate( filename.toUtf8().constData() );
293
294    QString text;
295    if( !myBuilder )
296        text = tr( "<i>No source selected<i>" );
297    else {
298        QString files = tr( "%Ln File(s)", 0, myBuilder->fileCount );
299        QString pieces = tr( "%Ln Piece(s)", 0, myBuilder->pieceCount );
300        text = tr( "%1 in %2; %3 @ %4" )
301                 .arg( Formatter::sizeToString( myBuilder->totalSize ) )
302                 .arg( files )
303                 .arg( pieces )
304                 .arg( Formatter::sizeToString( myBuilder->pieceSize ) );
305    }
306
307    mySourceLabel->setText( text );
308}
309
310
311// bah, there doesn't seem to be any cleaner way to override
312// QPlainTextEdit's default desire to be 12 lines tall
313class ShortPlainTextEdit: public QPlainTextEdit {
314    public:
315        virtual ~ShortPlainTextEdit( ) { }
316        ShortPlainTextEdit( QWidget * parent = 0 ): QPlainTextEdit(parent) { }
317        virtual QSize sizeHint ( ) const { return QSize( 256, 50 ); }
318};
319
320MakeDialog :: MakeDialog( Session & session, QWidget * parent ):
321    QDialog( parent, Qt::Dialog ),
322    mySession( session ),
323    myBuilder( 0 )
324{
325    setAcceptDrops( true );
326
327    connect( &myTimer, SIGNAL(timeout()), this, SLOT(onProgress()) );
328
329    setWindowTitle( tr( "New Torrent" ) );
330    QVBoxLayout * top = new QVBoxLayout( this );
331    top->setSpacing( HIG :: PAD );
332
333    HIG * hig = new HIG;
334    hig->setContentsMargins( 0, 0, 0, 0 );
335    hig->addSectionTitle( tr( "Files" ) );
336
337        QFileIconProvider iconProvider;
338        const int iconSize( style()->pixelMetric( QStyle::PM_SmallIconSize ) );
339        const QIcon folderIcon = iconProvider.icon( QFileIconProvider::Folder );
340        const QPixmap folderPixmap = folderIcon.pixmap( iconSize );
341        QPushButton * b = new QPushButton;
342        b->setIcon( folderPixmap );
343        b->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) );
344        myDestination = QDir::homePath();
345        b->setText( myDestination );
346        connect( b, SIGNAL(clicked(bool)),
347                 this, SLOT(onDestinationClicked(void)) );
348        myDestinationButton = b;
349        hig->addRow( tr( "Sa&ve to:" ), b );
350
351        myFolderRadio = new QRadioButton( tr( "Source F&older:" ) );
352        connect( myFolderRadio, SIGNAL(toggled(bool)),
353                 this, SLOT(onSourceChanged()) );
354        myFolderButton = new QPushButton;
355        myFolderButton->setIcon( folderPixmap );
356        myFolderButton->setText( tr( "(None)" ) );
357        myFolderButton->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) );
358        connect( myFolderButton, SIGNAL(clicked(bool)),
359                 this, SLOT(onFolderClicked(void)) );
360        hig->addRow( myFolderRadio, myFolderButton );
361        enableBuddyWhenChecked( myFolderRadio, myFolderButton );
362
363        const QIcon fileIcon = iconProvider.icon( QFileIconProvider::File );
364        const QPixmap filePixmap = fileIcon.pixmap( iconSize );
365        myFileRadio = new QRadioButton( tr( "Source &File:" ) );
366        myFileRadio->setChecked( true );
367        connect( myFileRadio, SIGNAL(toggled(bool)),
368                 this, SLOT(onSourceChanged()) );
369        myFileButton = new QPushButton;
370        myFileButton->setText( tr( "(None)" ) );
371        myFileButton->setIcon( filePixmap );
372        myFileButton->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) );
373        connect( myFileButton, SIGNAL(clicked(bool)),
374                 this, SLOT(onFileClicked(void)) );
375        hig->addRow( myFileRadio, myFileButton );
376        enableBuddyWhenChecked( myFileRadio, myFileButton );
377
378        mySourceLabel = new QLabel( this );
379        hig->addRow( tr( "" ), mySourceLabel );
380
381    hig->addSectionDivider( );
382    hig->addSectionTitle( tr( "Properties" ) );
383
384        hig->addWideControl( myTrackerEdit = new ShortPlainTextEdit );
385        const int height = fontMetrics().size( 0, QString::fromUtf8("\n\n\n\n") ).height( );
386        myTrackerEdit->setMinimumHeight( height );
387        hig->addTallRow( tr( "&Trackers:" ), myTrackerEdit );
388        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." ) );
389        l->setAlignment( Qt::AlignLeft );
390        hig->addRow( tr( "" ), l );
391        myTrackerEdit->resize( 500, height );
392
393        myCommentCheck = new QCheckBox( tr( "Co&mment" ) );
394        myCommentEdit = new QLineEdit( );
395        hig->addRow( myCommentCheck, myCommentEdit );
396        enableBuddyWhenChecked( myCommentCheck, myCommentEdit );
397
398        myPrivateCheck = hig->addWideCheckBox( tr( "&Private torrent" ), false );
399
400    hig->finish( );
401    top->addWidget( hig, 1 );
402
403    myButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok
404                                      | QDialogButtonBox::Close );
405    connect( myButtonBox, SIGNAL(clicked(QAbstractButton*)),
406             this, SLOT(onButtonBoxClicked(QAbstractButton*)) );
407
408    top->addWidget( myButtonBox );
409    onSourceChanged( );
410}
411
412MakeDialog :: ~MakeDialog( )
413{
414    if( myBuilder )
415        tr_metaInfoBuilderFree( myBuilder );
416}
417
418/***
419****
420***/
421
422void
423MakeDialog :: dragEnterEvent( QDragEnterEvent * event )
424{
425    const QMimeData * mime = event->mimeData( );
426
427    if( mime->urls().size() && QFile(mime->urls().front().path()).exists( ) )
428        event->acceptProposedAction();
429}
430
431void
432MakeDialog :: dropEvent( QDropEvent * event )
433{
434    const QString filename = event->mimeData()->urls().front().path();
435    const QFileInfo fileInfo( filename );
436
437    if( fileInfo.exists( ) )
438    {
439        if( fileInfo.isDir( ) )
440        {
441            myFolderRadio->setChecked( true );
442            onFolderSelected( filename  );
443        }
444        else // it's a file
445        {
446            myFileRadio->setChecked( true );
447            onFileSelected( filename );
448        }
449    }
450}
Note: See TracBrowser for help on using the repository browser.