transmission/qt/make-dialog.cc

332 lines
9.6 KiB
C++

/*
* This file Copyright (C) 2009 Charles Kerr <charles@transmissionbt.com>
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id$
*/
#include <cassert>
#include <iostream>
#include <QDialogButtonBox>
#include <QTimer>
#include <QFileDialog>
#include <QLabel>
#include <QStyle>
#include <QPushButton>
#include <QLineEdit>
#include <QPlainTextEdit>
#include <QCheckBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QList>
#include <QProgressBar>
#include <libtransmission/transmission.h>
#include <libtransmission/makemeta.h>
#include <libtransmission/utils.h>
#include "hig.h"
#include "make-dialog.h"
#include "squeezelabel.h"
#include "qticonloader.h"
#include "utils.h"
MakeDialog :: MakeDialog( Session & mySession, QWidget * parent ):
QDialog( parent, Qt::Dialog ),
myBuilder( 0 ),
myIsBuilding( 0 )
{
Q_UNUSED( mySession );
connect( &myTimer, SIGNAL(timeout()), this, SLOT(onProgress()) );
setWindowTitle( tr( "New Torrent" ) );
QVBoxLayout * top = new QVBoxLayout( this );
top->setSpacing( HIG :: PAD );
HIG * hig = new HIG;
hig->setContentsMargins( 0, 0, 0, 0 );
hig->addSectionTitle( tr( "Source" ) );
hig->addWideControl( mySourceEdit = new QLineEdit );
connect( mySourceEdit, SIGNAL(textChanged(const QString&)), this, SLOT(refresh()));
connect( mySourceEdit, SIGNAL(editingFinished()), this, SLOT(onSourceChanged()));
QHBoxLayout * h = new QHBoxLayout;
h->setContentsMargins( 0, 0, 0, 0 );
h->addWidget( mySourceLabel = new QLabel( tr( "<i>No source selected</i>" ) ) );
mySourceLabel->setMinimumWidth( fontMetrics().size( 0, "420 KB in 412 Files; 402 Pieces @ 42 KB each" ).width( ) );
h->addStretch( 1 );
h->setSpacing( HIG :: PAD );
QPushButton * b = new QPushButton( style()->standardIcon( QStyle::SP_DirIcon ), tr( "F&older" ) );
connect( b, SIGNAL(clicked(bool)), this, SLOT(onFolderButtonPressed()));
h->addWidget( b );
b = new QPushButton( style()->standardIcon( QStyle::SP_FileIcon ), tr( "&File" ) );
connect( b, SIGNAL(clicked(bool)), this, SLOT(onFileButtonPressed()));
h->addWidget( b );
hig->addWideControl( h );
hig->addSectionDivider( );
hig->addSectionTitle( tr( "Trackers" ) );
hig->addWideControl( myTrackerEdit = new QPlainTextEdit );
connect( myTrackerEdit, SIGNAL(textChanged()), this, SLOT(refresh()) );
const int height = fontMetrics().size( 0, "\n\n\n\n" ).height( );
myTrackerEdit->setMinimumHeight( height );
myTrackerEdit->setMaximumHeight( height );
hig->addWideControl( new QLabel( tr( "Separate tiers with an empty line" ) ) );
hig->addSectionDivider( );
hig->addSectionTitle( tr( "Options" ) );
hig->addRow( tr( "Commen&t:" ), myCommentEdit = new QLineEdit );
hig->addWideControl( myPrivateCheck = new QCheckBox( "&Private torrent" ) );
hig->addSectionDivider( );
hig->addSectionDivider( );
hig->addSectionTitle( tr( "Progress" ) );
QProgressBar * p = myProgressBar = new QProgressBar;
p->setTextVisible( false );
p->setMinimum( 0 );
p->setMaximum( 100 );
p->setValue( 0 );
hig->addWideControl( p );
hig->addWideControl( myProgressLabel = new QLabel( "<i>No source selected</i>" ) );
hig->finish( );
top->addWidget( hig, 1 );
//QFrame * f = new QFrame;
//f->setFrameShape( QFrame :: HLine );
//top->addWidget( f );
QIcon icon;
QDialogButtonBox * buttons = new QDialogButtonBox( this );
icon = style()->standardIcon( QStyle::SP_FileDialogNewFolder );
icon = QtIconLoader :: icon( "document-new", icon );
b = myMakeButton = new QPushButton( icon, tr( "&New Torrent" ) );
buttons->addButton( b, QDialogButtonBox::ActionRole );
icon = style()->standardIcon( QStyle::SP_DialogCancelButton );
icon = QtIconLoader :: icon( "process-stop", icon );
b = myStopButton = new QPushButton( icon, tr( "&Stop" ) );
buttons->addButton( b, QDialogButtonBox::RejectRole );
icon = style()->standardIcon( QStyle::SP_DialogCloseButton );
icon = QtIconLoader :: icon( "window-close", icon );
b = myCloseButton = new QPushButton( icon, tr( "&Close" ) );
buttons->addButton( b, QDialogButtonBox::AcceptRole );
connect( buttons, SIGNAL(clicked(QAbstractButton*)),
this, SLOT(onButtonBoxClicked(QAbstractButton*)) );
top->addWidget( buttons );
refresh( );
}
MakeDialog :: ~MakeDialog( )
{
if( myBuilder )
tr_metaInfoBuilderFree( myBuilder );
}
/***
****
***/
QString
MakeDialog :: getResult( ) const
{
QString str;
switch( myBuilder->result )
{
case TR_MAKEMETA_OK:
str = tr( "%1.torrent created!" ).arg( myBuilder->top );
break;
case TR_MAKEMETA_URL:
str = tr( "Error: Invalid URL" );
break;
case TR_MAKEMETA_CANCELLED:
str = tr( "Torrent creation cancelled" );
break;
case TR_MAKEMETA_IO_READ:
str = tr( "Error: Couldn't read \"%1\": %2" )
.arg( myBuilder->errfile )
.arg( tr_strerror( myBuilder->my_errno ) );
break;
case TR_MAKEMETA_IO_WRITE:
str = tr( "Error: Couldn't create \"%1\": %2" )
.arg( myBuilder->errfile )
.arg( tr_strerror( myBuilder->my_errno ) );
break;
}
return str;
}
void
MakeDialog :: refresh( )
{
QString progressText;
bool canBuild = true;
if( myIsBuilding ) {
progressText = tr( "Creating %1.torrent" ).arg( myBuilder->top );
canBuild = false;
} else if( mySourceEdit->text().trimmed().isEmpty() ) {
progressText = tr( "<i>No source selected<i>" );
canBuild = false;
} else if( myTrackerEdit->toPlainText().isEmpty() ) {
progressText = tr( "<i>No tracker announce URLs listed</i>" );
canBuild = false;
} else if( myBuilder && myBuilder->isDone ) {
progressText = getResult( );
canBuild = true;
}
myProgressLabel->setText( progressText );
myMakeButton->setEnabled( canBuild && myBuilder );
myCloseButton->setEnabled( !myIsBuilding );
myStopButton->setEnabled( myIsBuilding );
}
void
MakeDialog :: setIsBuilding( bool isBuilding )
{
myIsBuilding = isBuilding;
if( myBuilder )
myBuilder->result = TR_MAKEMETA_OK;
if( isBuilding )
myProgressBar->setValue( 0 );
if( isBuilding )
myTimer.start( 100 );
else
myTimer.stop( );
refresh( );
}
void
MakeDialog :: onProgress( )
{
const double denom = myBuilder->pieceCount ? myBuilder->pieceCount : 1;
myProgressBar->setValue( (int) ((100.0 * myBuilder->pieceIndex) / denom ) );
refresh( );
if( myBuilder->isDone )
setIsBuilding( false );
//tr_metainfo_builder_err result;
}
void
MakeDialog :: makeTorrent( )
{
if( !myBuilder )
return;
int tier = 0;
QList<tr_tracker_info> trackers;
foreach( QString line, myTrackerEdit->toPlainText().split("\n") ) {
line = line.trimmed( );
if( line.isEmpty( ) )
++tier;
else {
tr_tracker_info tmp;
tmp.announce = tr_strdup( line.toUtf8().constData( ) );
tmp.tier = tier;
std::cerr << "tier [" << tmp.tier << "] announce [" << tmp.announce << ']' << std::endl;
trackers.append( tmp );
}
}
tr_makeMetaInfo( myBuilder,
NULL,
&trackers.front(),
trackers.size(),
myCommentEdit->text().toUtf8().constData(),
myPrivateCheck->isChecked() );
refresh( );
setIsBuilding( true );
}
void
MakeDialog :: onButtonBoxClicked( QAbstractButton * button )
{
if( button == myMakeButton )
makeTorrent( );
if( button == myStopButton )
myBuilder->abortFlag = true;
if( button == myCloseButton )
deleteLater( );
}
/***
****
***/
void
MakeDialog :: onSourceChanged( )
{
if( myBuilder ) {
tr_metaInfoBuilderFree( myBuilder );
myBuilder = 0;
}
const QString filename = mySourceEdit->text( );
if( !filename.isEmpty( ) )
myBuilder = tr_metaInfoBuilderCreate( filename.toUtf8().constData() );
QString text;
if( !myBuilder )
text = tr( "<i>No source selected<i>" );
else {
QString files = tr( "%Ln File(s)", 0, myBuilder->fileCount );
QString pieces = tr( "%Ln Piece(s)", 0, myBuilder->pieceCount );
text = tr( "%1 in %2; %3 @ %4" )
.arg( Utils::sizeToString( myBuilder->totalSize ) )
.arg( files )
.arg( pieces )
.arg( Utils::sizeToString( myBuilder->pieceSize ) );
}
mySourceLabel->setText( text );
refresh( );
}
void
MakeDialog :: onFileSelectedInDialog( const QString& path )
{
mySourceEdit->setText( path );
onSourceChanged( );
}
void
MakeDialog :: onFolderButtonPressed( )
{
QFileDialog * f = new QFileDialog( this );
f->setFileMode( QFileDialog :: Directory );
connect( f, SIGNAL(fileSelected(const QString&)), this, SLOT(onFileSelectedInDialog(const QString&)));
f->show( );
}
void
MakeDialog :: onFileButtonPressed( )
{
QFileDialog * f = new QFileDialog( this );
f->setFileMode( QFileDialog :: ExistingFile );
connect( f, SIGNAL(fileSelected(const QString&)), this, SLOT(onFileSelectedInDialog(const QString&)));
f->show( );
}