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

Last change on this file since 11824 was 11824, checked in by jordan, 11 years ago

(trunk qt) in the "new torrent" dialog, have the "save to" and "source folder" file dialogs be QFileDialog::DirectoryOnly? rather than QFileDialog::Directory

  • Property svn:keywords set to Date Rev Author Id
File size: 13.5 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 11824 2011-02-03 22:13:31Z 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 <QPlainTextEdit>
25#include <QProgressBar>
26#include <QPushButton>
27#include <QRadioButton>
28#include <QSize>
29#include <QStyle>
30#include <QTimer>
31#include <QVBoxLayout>
32
33#include <libtransmission/transmission.h>
34#include <libtransmission/makemeta.h>
35#include <libtransmission/utils.h>
36
37#include "formatter.h"
38#include "hig.h"
39#include "make-dialog.h"
40#include "session.h"
41
42/***
43****
44***/
45
46void
47MakeDialog :: onNewDialogDestroyed( QObject * o )
48{
49    Q_UNUSED( o );
50
51    myTimer.stop( );
52}
53
54void
55MakeDialog :: onNewButtonBoxClicked( QAbstractButton * button )
56{
57    switch( myNewButtonBox->standardButton( button ) )
58    {
59        case QDialogButtonBox::Open:
60std::cerr << "calling mySession.addTorrent( " << qPrintable(myTarget) << ", " << qPrintable(QFileInfo(myBuilder->top).dir().path()) << ')' << std::endl;
61            mySession.addNewlyCreatedTorrent( myTarget, QFileInfo(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 base( QFileInfo(b->top).baseName() );
83    QString str;
84    if( !b->isDone )
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 );
97
98    // buttons
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 );
102}
103
104
105void
106MakeDialog :: makeTorrent( )
107{
108    if( !myBuilder )
109        return;
110
111    // get the tiers
112    int tier = 0;
113    QList<tr_tracker_info> trackers;
114    foreach( QString line, myTrackerEdit->toPlainText().split("\n") ) {
115        line = line.trimmed( );
116        if( line.isEmpty( ) )
117            ++tier;
118        else {
119            tr_tracker_info tmp;
120            tmp.announce = tr_strdup( line.toUtf8().constData( ) );
121            tmp.tier = tier;
122            trackers.append( tmp );
123        }
124    }
125
126    // pop up the dialog
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 );
140    onProgress( );
141    dialog->show( );
142    connect( dialog, SIGNAL(destroyed(QObject*)),
143             this, SLOT(onNewDialogDestroyed(QObject*)) );
144    myTimer.start( 100 );
145
146    // the file to create
147    myTarget = QDir( myDestination ).filePath( QFileInfo(myBuilder->top).baseName() + ".torrent" );
148    std::cerr << qPrintable(myTarget) << std::endl;
149
150    // comment
151    QString comment;
152    if( myCommentCheck->isChecked() )
153        comment = myCommentEdit->text().toUtf8().constData();
154
155    // start making the torrent
156    tr_makeMetaInfo( myBuilder,
157                     myTarget.toUtf8().constData(),
158                     (trackers.isEmpty() ? 0 : &trackers.front()),
159                     trackers.size(),
160                     (comment.isEmpty() ? NULL : comment.toUtf8().constData()),
161                     myPrivateCheck->isChecked() );
162}
163
164/***
165****
166***/
167
168void
169MakeDialog :: onFileClicked( )
170{
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&)) );
175    d->show( );
176}
177void
178MakeDialog :: onFileSelected( const QStringList& list )
179{
180    if( !list.empty( ) )
181        onFileSelected( list.front( ) );
182}
183void
184MakeDialog :: onFileSelected( const QString& filename )
185{
186    myFile = filename;
187    myFileButton->setText( QFileInfo(myFile).fileName() );
188    onSourceChanged( );
189}
190
191void
192MakeDialog :: onFolderClicked( )
193{
194    QFileDialog * d = new QFileDialog( this, tr( "Select Folder" ) );
195    d->setFileMode( QFileDialog::DirectoryOnly );
196    connect( d, SIGNAL(filesSelected(const QStringList&)),
197             this, SLOT(onFolderSelected(const QStringList&)) );
198    d->show( );
199}
200void
201MakeDialog :: onFolderSelected( const QStringList& list )
202{
203    if( !list.empty( ) )
204        onFolderSelected( list.front( ) );
205}
206void
207MakeDialog :: onFolderSelected( const QString& filename )
208{
209    myFolder = filename;
210    myFolderButton->setText( QFileInfo(myFolder).fileName() );
211    onSourceChanged( );
212}
213
214void
215MakeDialog :: onDestinationClicked( )
216{
217    QFileDialog * d = new QFileDialog( this, tr( "Select Folder" ) );
218    d->setFileMode( QFileDialog::DirectoryOnly );
219    connect( d, SIGNAL(filesSelected(const QStringList&)),
220             this, SLOT(onDestinationSelected(const QStringList&)) );
221    d->show( );
222}
223void
224MakeDialog :: onDestinationSelected( const QStringList& list )
225{
226    if( !list.empty( ) )
227        onDestinationSelected( list.front() );
228}
229void
230MakeDialog :: onDestinationSelected( const QString& filename )
231{
232    myDestination = filename;
233    myDestinationButton->setText( QFileInfo(myDestination).fileName() );
234}
235
236void
237MakeDialog :: enableBuddyWhenChecked( QRadioButton * box, QWidget * buddy )
238{
239    connect( box, SIGNAL(toggled(bool)), buddy, SLOT(setEnabled(bool)) );
240    buddy->setEnabled( box->isChecked( ) );
241}
242void
243MakeDialog :: enableBuddyWhenChecked( QCheckBox * box, QWidget * buddy )
244{
245    connect( box, SIGNAL(toggled(bool)), buddy, SLOT(setEnabled(bool)) );
246    buddy->setEnabled( box->isChecked( ) );
247}
248
249QString
250MakeDialog :: getSource( ) const
251{
252    return myFileRadio->isChecked( ) ? myFile : myFolder;
253}
254
255void
256MakeDialog :: onButtonBoxClicked( QAbstractButton * button )
257{
258    switch( myButtonBox->standardButton( button ) )
259    {
260        case QDialogButtonBox::Ok:
261            makeTorrent( );
262            break;
263
264        default: // QDialogButtonBox::Close:
265            deleteLater( );
266            break;
267    }
268}
269
270/***
271****
272***/
273
274void
275MakeDialog :: onSourceChanged( )
276{
277    if( myBuilder )
278    {
279        tr_metaInfoBuilderFree( myBuilder );
280        myBuilder = 0;
281    }
282
283    const QString filename = getSource( );
284    if( !filename.isEmpty( ) )
285        myBuilder = tr_metaInfoBuilderCreate( filename.toUtf8().constData() );
286
287    QString text;
288    if( !myBuilder )
289        text = tr( "<i>No source selected<i>" );
290    else {
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 ) )
295                 .arg( files )
296                 .arg( pieces )
297                 .arg( Formatter::sizeToString( myBuilder->pieceSize ) );
298    }
299
300    mySourceLabel->setText( text );
301}
302
303
304// bah, there doesn't seem to be any cleaner way to override
305// QPlainTextEdit's default desire to be 12 lines tall
306class ShortPlainTextEdit: public QPlainTextEdit {
307    public:
308        virtual ~ShortPlainTextEdit( ) { }
309        ShortPlainTextEdit( QWidget * parent = 0 ): QPlainTextEdit(parent) { }
310        virtual QSize sizeHint ( ) const { return QSize( 256, 50 ); }
311};
312
313MakeDialog :: MakeDialog( Session & session, QWidget * parent ):
314    QDialog( parent, Qt::Dialog ),
315    mySession( session ),
316    myBuilder( 0 )
317{
318    setAcceptDrops( true );
319
320    connect( &myTimer, SIGNAL(timeout()), this, SLOT(onProgress()) );
321
322    setWindowTitle( tr( "New Torrent" ) );
323    QVBoxLayout * top = new QVBoxLayout( this );
324    top->setSpacing( HIG :: PAD );
325
326    HIG * hig = new HIG;
327    hig->setContentsMargins( 0, 0, 0, 0 );
328    hig->addSectionTitle( tr( "Files" ) );
329
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 );
343
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 );
355
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 );
370
371        mySourceLabel = new QLabel( this );
372        hig->addRow( tr( "" ), mySourceLabel );
373
374    hig->addSectionDivider( );
375    hig->addSectionTitle( tr( "Properties" ) );
376
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 );
385
386        myCommentCheck = new QCheckBox( tr( "Co&mment" ) );
387        myCommentEdit = new QLineEdit( );
388        hig->addRow( myCommentCheck, myCommentEdit );
389        enableBuddyWhenChecked( myCommentCheck, myCommentEdit );
390
391        myPrivateCheck = hig->addWideCheckBox( tr( "&Private torrent" ), false );
392
393    hig->finish( );
394    top->addWidget( hig, 1 );
395
396    myButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok
397                                      | QDialogButtonBox::Close );
398    connect( myButtonBox, SIGNAL(clicked(QAbstractButton*)),
399             this, SLOT(onButtonBoxClicked(QAbstractButton*)) );
400
401    top->addWidget( myButtonBox );
402    onSourceChanged( );
403}
404
405MakeDialog :: ~MakeDialog( )
406{
407    if( myBuilder )
408        tr_metaInfoBuilderFree( myBuilder );
409}
410
411/***
412****
413***/
414
415void
416MakeDialog :: dragEnterEvent( QDragEnterEvent * event )
417{
418    const QMimeData * mime = event->mimeData( );
419
420    if( mime->urls().size() && QFile(mime->urls().front().path()).exists( ) )
421        event->acceptProposedAction();
422}
423
424void
425MakeDialog :: dropEvent( QDropEvent * event )
426{
427    const QString filename = event->mimeData()->urls().front().path();
428    const QFileInfo fileInfo( filename );
429
430    if( fileInfo.exists( ) )
431    {
432        if( fileInfo.isDir( ) )
433        {
434            myFolderRadio->setChecked( true );
435            onFolderSelected( filename  );
436        }
437        else // it's a file
438        {
439            myFileRadio->setChecked( true );
440            onFileSelected( filename );
441        }
442    }
443}
Note: See TracBrowser for help on using the repository browser.