(trunk) #1220 'change top folder names' -- add file-renaming to the Qt client

This commit is contained in:
Jordan Lee 2013-01-20 01:31:58 +00:00
parent 10e4c297d6
commit dd955b121e
11 changed files with 208 additions and 73 deletions

View File

@ -429,11 +429,11 @@
string | value type & description
---------------------------------+-------------------------------------------------
"ids" | array the torrent torrent list, as described in 3.1
| (though, this function doesn't make sense for >1 torrent)
| (must only be 1 torrent)
"path" | string the path to the file or folder that will be renamed
"name" | string the file or folder's new name
Response arguments: none
Response arguments: "path", "name", and "id", holding the torrent ID integer
4. Session Requests

View File

@ -353,59 +353,6 @@ torrentRemove (tr_session * session,
return NULL;
}
static void
torrentRenamePathDone (tr_torrent * tor UNUSED,
const char * oldpath UNUSED,
const char * newname UNUSED,
int error,
void * user_data)
{
*(int*)user_data = error;
}
static const char *
torrentRenamePath (tr_session * session,
tr_variant * args_in,
tr_variant * args_out UNUSED,
struct tr_rpc_idle_data * idle_data UNUSED)
{
const char * oldpath;
const char * newname;
const char * ret = NULL;
if (!tr_variantDictFindStr (args_in, TR_KEY_path, &oldpath, NULL))
{
ret = "no path specified";
}
else if (!tr_variantDictFindStr (args_in, TR_KEY_name, &newname, NULL))
{
ret = "no name specified";
}
else
{
int torrentCount;
tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount);
if (torrentCount != 1)
{
ret = "torent-rename-path requires 1 torrent";
}
else
{
int error = -1;
tr_torrentRenamePath (torrents[0], oldpath, newname, torrentRenamePathDone, &error);
assert (error != -1);
if (error != 0)
ret = tr_strerror (error);
}
tr_free (torrents);
}
return ret;
}
static const char*
torrentReannounce (tr_session * session,
tr_variant * args_in,
@ -478,8 +425,7 @@ addFileStats (const tr_torrent * tor, tr_variant * list)
}
static void
addFiles (const tr_torrent * tor,
tr_variant * list)
addFiles (const tr_torrent * tor, tr_variant * list)
{
tr_file_index_t i;
tr_file_index_t n;
@ -1365,6 +1311,57 @@ torrentSetLocation (tr_session * session,
****
***/
static void
torrentRenamePathDone (tr_torrent * tor,
const char * oldpath,
const char * newname,
int error,
void * user_data)
{
const char * result;
struct tr_rpc_idle_data * data = user_data;
tr_variantDictAddInt (data->args_out, TR_KEY_id, tr_torrentId(tor));
tr_variantDictAddStr (data->args_out, TR_KEY_path, oldpath);
tr_variantDictAddStr (data->args_out, TR_KEY_name, newname);
if (error == 0)
result = NULL;
else
result = tr_strerror (error);
tr_idle_function_done (data, result);
}
static const char*
torrentRenamePath (tr_session * session,
tr_variant * args_in,
tr_variant * args_out UNUSED,
struct tr_rpc_idle_data * idle_data)
{
int torrentCount;
tr_torrent ** torrents;
const char * oldpath = NULL;
const char * newname = NULL;
tr_variantDictFindStr (args_in, TR_KEY_path, &oldpath, NULL);
tr_variantDictFindStr (args_in, TR_KEY_name, &newname, NULL);
torrents = getTorrents (session, args_in, &torrentCount);
if (torrentCount == 1)
tr_torrentRenamePath (torrents[0], oldpath, newname, torrentRenamePathDone, idle_data);
else
tr_idle_function_done (idle_data, "torrent-rename-path requires 1 torrent");
/* cleanup */
tr_free (torrents);
return NULL; /* ignored */
}
/***
****
***/
static void
portTested (tr_session * session UNUSED,
bool did_connect UNUSED,
@ -1394,8 +1391,8 @@ portTested (tr_session * session UNUSED,
static const char*
portTest (tr_session * session,
tr_variant * args_in UNUSED,
tr_variant * args_out UNUSED,
tr_variant * args_in UNUSED,
tr_variant * args_out UNUSED,
struct tr_rpc_idle_data * idle_data)
{
const int port = tr_sessionGetPeerPort (session);
@ -1612,8 +1609,8 @@ fileListFromList (tr_variant * list, tr_file_index_t * setmeCount)
static const char*
torrentAdd (tr_session * session,
tr_variant * args_in,
tr_variant * args_out UNUSED,
tr_variant * args_in,
tr_variant * args_out UNUSED,
struct tr_rpc_idle_data * idle_data)
{
const char * filename = NULL;
@ -1986,7 +1983,7 @@ methods[] =
{ "torrent-add", false, torrentAdd },
{ "torrent-get", true, torrentGet },
{ "torrent-remove", true, torrentRemove },
{ "torrent-rename-path", true, torrentRenamePath },
{ "torrent-rename-path", false, torrentRenamePath },
{ "torrent-set", true, torrentSet },
{ "torrent-set-location", true, torrentSetLocation },
{ "torrent-start", true, torrentStart },
@ -2069,7 +2066,7 @@ request_exec (tr_session * session,
tr_variantDictAddInt (&response, TR_KEY_tag, tag);
buf = tr_variantToBuf (&response, TR_VARIANT_FMT_JSON_LEAN);
(*callback)(session, buf, callback_user_data);
(*callback)(session, buf, callback_user_data);
evbuffer_free (buf);
tr_variantFree (&response);
@ -2086,7 +2083,7 @@ request_exec (tr_session * session,
data->args_out = tr_variantDictAddDict (data->response, TR_KEY_arguments, 0);
data->callback = callback;
data->callback_user_data = callback_user_data;
(*methods[i].func)(session, args_in, data->args_out, data);
(*methods[i].func)(session, args_in, data->args_out, data);
}
}

View File

@ -3491,6 +3491,8 @@ torrentRenamePath (void * vdata)
****
***/
tor->anyDate = tr_time ();
/* callback */
if (data->callback != NULL)
(*data->callback)(tor, data->oldpath, data->newname, error, data->callback_user_data);

View File

@ -202,8 +202,10 @@ Details :: setIds( const QSet<int>& ids )
// stop listening to the old torrents
foreach( int id, myIds ) {
const Torrent * tor = myModel.getTorrentFromId( id );
if( tor )
if( tor ) {
disconnect( tor, SIGNAL(torrentChanged(int)), this, SLOT(onTorrentChanged()) );
disconnect( tor, SIGNAL(torrentFileListRebuilt(int)), this, SLOT(onTorrentFileListRebuilt()) );
}
}
myFileTreeView->clear( );
@ -213,8 +215,10 @@ Details :: setIds( const QSet<int>& ids )
// listen to the new torrents
foreach( int id, myIds ) {
const Torrent * tor = myModel.getTorrentFromId( id );
if( tor )
if( tor ) {
connect( tor, SIGNAL(torrentChanged(int)), this, SLOT(onTorrentChanged()) );
connect( tor, SIGNAL(torrentFileListRebuilt(int)), this, SLOT(onTorrentFileListRebuilt()) );
}
}
foreach( QWidget * w, myWidgets )
@ -295,6 +299,13 @@ Details :: onTorrentChanged( )
}
}
void
Details :: onTorrentFileListRebuilt( )
{
myFilesDirty = true;
onTorrentChanged( );
}
namespace
{
void setIfIdle( QComboBox * box, int i )
@ -829,10 +840,11 @@ Details :: refresh( )
}
myPeers = peers2;
if( !single || myFilesDirty )
myFileTreeView->clear( );
if( single )
myFileTreeView->update( torrents[0]->files( ) , myChangedTorrents );
else
myFileTreeView->clear( );
myFilesDirty = false;
myChangedTorrents = false;
myHavePendingRefresh = false;
@ -1307,6 +1319,9 @@ Details :: createFilesTab( )
connect( myFileTreeView, SIGNAL( wantedChanged(const QSet<int>&, bool)),
this, SLOT( onFileWantedChanged(const QSet<int>&, bool)));
connect( myFileTreeView, SIGNAL( pathEdited(const QString&, const QString&)),
this, SLOT (onPathEdited(const QString&, const QString&)));
return myFileTreeView;
}
@ -1341,3 +1356,9 @@ Details :: onFileWantedChanged (const QSet<int>& indices, bool wanted)
mySession.torrentSet (myIds, key, indices.toList());
getNewData ();
}
void
Details :: onPathEdited (const QString& oldpath, const QString& newname)
{
mySession.torrentRenamePath (myIds, oldpath, newname);
}

View File

@ -49,6 +49,7 @@ class Details: public QDialog
private slots:
void onTorrentChanged( );
void onTorrentFileListRebuilt( );
void onTimer( );
public:
@ -135,11 +136,14 @@ class Details: public QDialog
FileTreeView * myFileTreeView;
bool myFilesDirty;
private slots:
void refreshPref( int key );
void onBandwidthPriorityChanged( int );
void onFilePriorityChanged( const QSet<int>& fileIndices, int );
void onFileWantedChanged( const QSet<int>& fileIndices, bool );
void onPathEdited (const QString& oldpath, const QString& newname);
void onHonorsSessionLimitsToggled( bool );
void onDownloadLimitedToggled( bool );
void onSpinBoxEditingFinished( );

View File

@ -318,12 +318,39 @@ FileTreeModel :: flags( const QModelIndex& index ) const
{
int i( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
if( index.column( ) == COL_NAME )
i |= Qt::ItemIsEditable;
if( index.column( ) == COL_WANTED )
i |= Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
return (Qt::ItemFlags)i;
}
bool
FileTreeModel :: setData (const QModelIndex& index, const QVariant& newname, int role)
{
if (role == Qt::EditRole)
{
QString oldpath;
QModelIndex walk = index;
FileTreeItem * item = static_cast<FileTreeItem*>(index.internalPointer());
while (item && !item->name().isEmpty())
{
if (oldpath.isEmpty())
oldpath = item->name();
else
oldpath = item->name() + "/" + oldpath;
item = item->parent ();
}
emit pathEdited (oldpath, newname.toString());
}
return false; // don't update the view until the session confirms the change
}
QVariant
FileTreeModel :: headerData( int column, Qt::Orientation orientation, int role ) const
{
@ -681,6 +708,9 @@ FileTreeView :: FileTreeView( QWidget * parent ):
connect( &myModel, SIGNAL(wantedChanged(const QSet<int>&, bool)),
this, SIGNAL(wantedChanged(const QSet<int>&, bool)));
connect( &myModel, SIGNAL(pathEdited(const QString&, const QString&)),
this, SIGNAL(pathEdited(const QString&, const QString&)));
}
FileTreeView :: ~FileTreeView( )

View File

@ -101,10 +101,12 @@ class FileTreeModel: public QAbstractItemModel
QModelIndex parent( const QModelIndex& child, int column ) const;
int rowCount( const QModelIndex& parent = QModelIndex( ) ) const;
int columnCount( const QModelIndex &parent = QModelIndex( ) ) const;
virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
signals:
void priorityChanged( const QSet<int>& fileIndices, int );
void wantedChanged( const QSet<int>& fileIndices, bool );
void pathEdited (const QString& oldpath, const QString& newname);
public:
void clear( );
@ -154,6 +156,7 @@ class FileTreeView: public QTreeView
signals:
void priorityChanged( const QSet<int>& fileIndices, int );
void wantedChanged( const QSet<int>& fileIndices, bool );
void pathEdited (const QString& oldpath, const QString& newname);
protected:
bool eventFilter( QObject *, QEvent * );

View File

@ -27,6 +27,7 @@
#include <QStringList>
#include <QStyle>
#include <QTextStream>
#include <QTimer>
#include <curl/curl.h>
@ -60,6 +61,7 @@ namespace
TAG_ADD_TORRENT,
TAG_PORT_TEST,
TAG_MAGNET_LINK,
TAG_RENAME_PATH,
FIRST_UNIQUE_TAG
};
@ -246,7 +248,8 @@ Session :: Session( const char * configDir, Prefs& prefs ):
myPrefs( prefs ),
mySession( 0 ),
myConfigDir( QString::fromUtf8( configDir ) ),
myNAM( 0 )
myNAM( 0 ),
myResponseTimer (this)
{
myStats.ratio = TR_RATIO_NA;
myStats.uploadedBytes = 0;
@ -257,6 +260,9 @@ Session :: Session( const char * configDir, Prefs& prefs ):
myCumulativeStats = myStats;
connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(updatePref(int)) );
connect (&myResponseTimer, SIGNAL(timeout()), this, SLOT(onResponseTimer()));
myResponseTimer.setSingleShot (true);
}
Session :: ~Session( )
@ -494,6 +500,21 @@ Session :: torrentSetLocation( const QSet<int>& ids, const QString& location, bo
tr_variantFree (&top);
}
void
Session :: torrentRenamePath (const QSet<int>& ids, const QString& oldpath, const QString& newname)
{
tr_variant top;
tr_variantInitDict (&top, 2);
tr_variantDictAddStr (&top, TR_KEY_method, "torrent-rename-path");
tr_variantDictAddInt (&top, TR_KEY_tag, TAG_RENAME_PATH);
tr_variant * args (tr_variantDictAddDict(&top, TR_KEY_arguments, 3));
addOptionalIds (args, ids);
tr_variantDictAddStr (args, TR_KEY_path, oldpath.toUtf8().constData());
tr_variantDictAddStr (args, TR_KEY_name, newname.toUtf8().constData());
exec (&top);
tr_variantFree (&top);
}
void
Session :: refreshTorrents( const QSet<int>& ids )
{
@ -635,11 +656,16 @@ Session :: exec( const tr_variant * request )
}
void
Session :: localSessionCallback( tr_session * session, struct evbuffer * json, void * self )
Session :: localSessionCallback( tr_session * session, struct evbuffer * json, void * vself )
{
Q_UNUSED( session );
Q_UNUSED (session);
((Session*)self)->parseResponse( (const char*) evbuffer_pullup( json, -1 ), evbuffer_get_length( json ) );
Session * self = static_cast<Session*>(vself);
self->myIdleJSON.append (QString ((const char*) evbuffer_pullup (json, -1)));
if (!self->myResponseTimer.isActive())
self->myResponseTimer.start(50);
}
#define REQUEST_DATA_PROPERTY_KEY "requestData"
@ -715,6 +741,19 @@ Session :: onFinished( QNetworkReply * reply )
reply->deleteLater();
}
void
Session :: onResponseTimer ()
{
QStringList responses = myIdleJSON;
myIdleJSON.clear();
foreach (QString response, responses)
{
const QByteArray utf8 (response.toUtf8());
parseResponse (utf8.constData(), utf8.length());
}
}
void
Session :: parseResponse( const char * json, size_t jsonLength )
{
@ -767,11 +806,43 @@ Session :: parseResponse( const char * json, size_t jsonLength )
break;
}
case TAG_RENAME_PATH:
{
int64_t id = 0;
const char * result = 0;
if( tr_variantDictFindStr (&top, TR_KEY_result, &result, 0) && strcmp (result, "success") )
{
const char * path = "";
const char * name = "";
tr_variantDictFindStr (args, TR_KEY_path, &path, 0);
tr_variantDictFindStr (args, TR_KEY_name, &name, 0);
const QString title = tr("Error Renaming Path");
const QString text = tr("<p><b>Unable to rename \"%1\" as \"%2\": %3.</b></p> <p>Please correct the errors and try again.</p>").arg(path).arg(name).arg(result);
QMessageBox * d = new QMessageBox( QMessageBox::Information, title, text,
QMessageBox::Close,
QApplication::activeWindow());
connect( d, SIGNAL(rejected()), d, SLOT(deleteLater()) );
d->show( );
}
else if (tr_variantDictFindInt (args, TR_KEY_id, &id) && id)
{
// let's get the updated file list
char * req = tr_strdup_printf ("{ \"arguments\": { \"fields\": [ \"files\", \"id\" ], \"ids\": %d }, \"method\": \"torrent-get\", \"tag\": %d }",
int(id),
int(TAG_SOME_TORRENTS));
exec (req);
tr_free (req);
}
break;
}
case TAG_PORT_TEST: {
bool isOpen = 0;
if( tr_variantDictFindDict( &top, TR_KEY_arguments, &args ) )
tr_variantDictFindBool( args, TR_KEY_port_is_open, &isOpen );
emit portTested( (bool)isOpen );
break;
}
case TAG_MAGNET_LINK: {

View File

@ -19,6 +19,8 @@
#include <QFileInfoList>
#include <QNetworkAccessManager>
#include <QString>
#include <QStringList>
#include <QTimer>
#include <QUrl>
class QStringList;
@ -101,7 +103,7 @@ class Session: public QObject
void torrentSet( const QSet<int>& ids, const tr_quark key, const QStringList& val );
void torrentSet( const QSet<int>& ids, const tr_quark key, const QPair<int,QString>& val);
void torrentSetLocation( const QSet<int>& ids, const QString& path, bool doMove );
void torrentRenamePath( const QSet<int>& ids, const QString& oldpath, const QString& newname );
public slots:
void pauseTorrents( const QSet<int>& torrentIds = QSet<int>() );
@ -129,6 +131,7 @@ class Session: public QObject
private slots:
void onFinished( QNetworkReply * reply );
void onResponseTimer( );
signals:
void executed( int64_t tag, const QString& result, struct tr_variant * arguments );
@ -150,11 +153,13 @@ class Session: public QObject
tr_session * mySession;
QString myConfigDir;
QString mySessionId;
QStringList myIdleJSON;
QUrl myUrl;
QNetworkAccessManager * myNAM;
struct tr_session_stats myStats;
struct tr_session_stats myCumulativeStats;
QString mySessionVersion;
QTimer myResponseTimer;
};
#endif

View File

@ -573,6 +573,7 @@ Torrent :: update (tr_variant * d)
updateMimeIcon ();
changed = true;
emit torrentFileListRebuilt (id ());
}
if (tr_variantDictFindList (d, TR_KEY_fileStats, &files))

View File

@ -188,6 +188,7 @@ class Torrent: public QObject
signals:
void torrentChanged( int id );
void torrentCompleted( int id );
void torrentFileListRebuilt( int id );
private: