Browse Source

Merge pull request #2254 from buinsky/master

WebUI: Some changes
adaptive-webui-19844
sledgehammer999 10 years ago
parent
commit
1820a03f1d
  1. 875
      src/qtlibtorrent/qtorrenthandle.cpp
  2. 170
      src/qtlibtorrent/qtorrenthandle.h
  3. 1636
      src/transferlistwidget.cpp
  4. 115
      src/transferlistwidget.h
  5. 123
      src/webui/abstractrequesthandler.cpp
  6. 33
      src/webui/btjson.cpp
  7. 29
      src/webui/requesthandler.cpp
  8. 2
      src/webui/requesthandler.h
  9. 231
      src/webui/www/private/index.html
  10. 25
      src/webui/www/public/filters.html
  11. 269
      src/webui/www/public/scripts/client.js
  12. 100
      src/webui/www/public/scripts/contextmenu.js
  13. 18
      src/webui/www/public/scripts/dynamicTable.js
  14. 60
      src/webui/www/public/scripts/mocha-init.js
  15. 10
      src/webui/www/public/transferlist.html

875
src/qtlibtorrent/qtorrenthandle.cpp

File diff suppressed because it is too large Load Diff

170
src/qtlibtorrent/qtorrenthandle.h

@ -42,7 +42,8 @@ QT_END_NAMESPACE @@ -42,7 +42,8 @@ QT_END_NAMESPACE
class QTorrentState
{
public:
enum {
enum
{
Unknown = -1,
Error,
@ -71,93 +72,96 @@ private: @@ -71,93 +72,96 @@ private:
// A wrapper for torrent_handle in libtorrent
// to interact well with Qt types
class QTorrentHandle : public libtorrent::torrent_handle {
class QTorrentHandle: public libtorrent::torrent_handle
{
public:
//
// Constructors
//
QTorrentHandle() {}
explicit QTorrentHandle(const libtorrent::torrent_handle& h);
//
// Getters
//
QString hash() const;
QString name() const;
QString current_tracker() const;
bool is_paused() const;
bool has_filtered_pieces() const;
libtorrent::size_type total_size() const;
libtorrent::size_type piece_length() const;
int num_pieces() const;
QString save_path() const;
QString save_path_parsed() const;
QStringList url_seeds() const;
libtorrent::size_type actual_size() const;
int num_files() const;
int queue_position() const;
bool is_queued() const;
QString filename_at(unsigned int index) const;
libtorrent::size_type filesize_at(unsigned int index) const;
QString filepath_at(unsigned int index) const;
QString orig_filepath_at(unsigned int index) const;
libtorrent::torrent_status::state_t state() const;
QString creator() const;
QString comment() const;
QStringList absolute_files_path() const;
QStringList absolute_files_path_uneeded() const;
bool has_missing_files() const;
bool is_seed() const;
bool is_checking() const;
bool is_sequential_download() const;
QString creation_date() const;
qlonglong creation_date_unix() const;
bool priv() const;
bool first_last_piece_first() const;
QString root_path() const;
QString firstFileSavePath() const;
bool has_error() const;
QString error() const;
void downloading_pieces(libtorrent::bitfield& bf) const;
bool has_metadata() const;
void file_progress(std::vector<libtorrent::size_type>& fp) const;
QTorrentState torrentState() const;
qulonglong eta() const;
//
// Setters
//
void pause() const;
void resume() const;
void remove_url_seed(const QString& seed) const;
void add_url_seed(const QString& seed) const;
void set_tracker_login(const QString& username, const QString& password) const;
void move_storage(const QString& path) const;
void prioritize_first_last_piece(bool b) const;
void rename_file(int index, const QString& name) const;
bool save_torrent_file(const QString& path) const;
void prioritize_files(const std::vector<int>& files) const;
void file_priority(int index, int priority) const;
//
// Operators
//
bool operator ==(const QTorrentHandle& new_h) const;
static bool is_paused(const libtorrent::torrent_status &status);
static int queue_position(const libtorrent::torrent_status &status);
static bool is_queued(const libtorrent::torrent_status &status);
static bool is_seed(const libtorrent::torrent_status &status);
static bool is_checking(const libtorrent::torrent_status &status);
static bool has_error(const libtorrent::torrent_status &status);
static float progress(const libtorrent::torrent_status &status);
static QString filepath_at(const libtorrent::torrent_info &info, unsigned int index);
//
// Constructors
//
QTorrentHandle() {}
explicit QTorrentHandle(const libtorrent::torrent_handle& h);
//
// Getters
//
QString hash() const;
QString name() const;
QString current_tracker() const;
bool is_paused() const;
bool has_filtered_pieces() const;
libtorrent::size_type total_size() const;
libtorrent::size_type piece_length() const;
int num_pieces() const;
QString save_path() const;
QString save_path_parsed() const;
QStringList url_seeds() const;
libtorrent::size_type actual_size() const;
int num_files() const;
int queue_position() const;
bool is_queued() const;
QString filename_at(unsigned int index) const;
libtorrent::size_type filesize_at(unsigned int index) const;
QString filepath_at(unsigned int index) const;
QString orig_filepath_at(unsigned int index) const;
libtorrent::torrent_status::state_t state() const;
QString creator() const;
QString comment() const;
QStringList absolute_files_path() const;
QStringList absolute_files_path_uneeded() const;
bool has_missing_files() const;
bool is_seed() const;
bool is_checking() const;
bool is_sequential_download() const;
QString creation_date() const;
qlonglong creation_date_unix() const;
bool priv() const;
bool first_last_piece_first() const;
QString root_path() const;
QString firstFileSavePath() const;
bool has_error() const;
QString error() const;
void downloading_pieces(libtorrent::bitfield& bf) const;
bool has_metadata() const;
void file_progress(std::vector<libtorrent::size_type>& fp) const;
QTorrentState torrentState() const;
qulonglong eta() const;
void toggleSequentialDownload();
void toggleFirstLastPiecePrio();
//
// Setters
//
void pause() const;
void resume() const;
void remove_url_seed(const QString& seed) const;
void add_url_seed(const QString& seed) const;
void set_tracker_login(const QString& username, const QString& password) const;
void move_storage(const QString& path) const;
void prioritize_first_last_piece(bool b) const;
void rename_file(int index, const QString& name) const;
bool save_torrent_file(const QString& path) const;
void prioritize_files(const std::vector<int>& files) const;
void file_priority(int index, int priority) const;
//
// Operators
//
bool operator ==(const QTorrentHandle& new_h) const;
static bool is_paused(const libtorrent::torrent_status &status);
static int queue_position(const libtorrent::torrent_status &status);
static bool is_queued(const libtorrent::torrent_status &status);
static bool is_seed(const libtorrent::torrent_status &status);
static bool is_checking(const libtorrent::torrent_status &status);
static bool has_error(const libtorrent::torrent_status &status);
static float progress(const libtorrent::torrent_status &status);
static QString filepath_at(const libtorrent::torrent_info &info, unsigned int index);
private:
void prioritize_first_last_piece(int file_index, bool b) const;
void prioritize_first_last_piece(int file_index, bool b) const;
};

1636
src/transferlistwidget.cpp

File diff suppressed because it is too large Load Diff

115
src/transferlistwidget.h

@ -47,77 +47,78 @@ class QSortFilterProxyModel; @@ -47,77 +47,78 @@ class QSortFilterProxyModel;
class QStandardItemModel;
QT_END_NAMESPACE
class TransferListWidget: public QTreeView {
Q_OBJECT
class TransferListWidget: public QTreeView
{
Q_OBJECT
public:
TransferListWidget(QWidget *parent, MainWindow *main_window, QBtSession* BTSession);
~TransferListWidget();
TorrentModel* getSourceModel() const;
TransferListWidget(QWidget *parent, MainWindow *main_window, QBtSession* BTSession);
~TransferListWidget();
TorrentModel* getSourceModel() const;
public slots:
void setSelectionLabel(QString label);
void setRefreshInterval(int t);
void setSelectedTorrentsLocation();
void startSelectedTorrents();
void startVisibleTorrents();
void pauseSelectedTorrents();
void pauseVisibleTorrents();
void deleteSelectedTorrents();
void deleteVisibleTorrents();
void increasePrioSelectedTorrents();
void decreasePrioSelectedTorrents();
void topPrioSelectedTorrents();
void bottomPrioSelectedTorrents();
void copySelectedMagnetURIs() const;
void openSelectedTorrentsFolder() const;
void recheckSelectedTorrents();
void setDlLimitSelectedTorrents();
void setUpLimitSelectedTorrents();
void setMaxRatioSelectedTorrents();
void previewSelectedTorrents();
void hidePriorityColumn(bool hide);
void displayDLHoSMenu(const QPoint&);
void applyNameFilter(const QString& name);
void applyStatusFilter(int f);
void applyLabelFilterAll();
void applyLabelFilter(QString label);
void previewFile(QString filePath);
void removeLabelFromRows(QString label);
void renameSelectedTorrent();
void setSelectionLabel(QString label);
void setRefreshInterval(int t);
void setSelectedTorrentsLocation();
void startSelectedTorrents();
void startVisibleTorrents();
void pauseSelectedTorrents();
void pauseVisibleTorrents();
void deleteSelectedTorrents();
void deleteVisibleTorrents();
void increasePrioSelectedTorrents();
void decreasePrioSelectedTorrents();
void topPrioSelectedTorrents();
void bottomPrioSelectedTorrents();
void copySelectedMagnetURIs() const;
void openSelectedTorrentsFolder() const;
void recheckSelectedTorrents();
void setDlLimitSelectedTorrents();
void setUpLimitSelectedTorrents();
void setMaxRatioSelectedTorrents();
void previewSelectedTorrents();
void hidePriorityColumn(bool hide);
void displayDLHoSMenu(const QPoint&);
void applyNameFilter(const QString& name);
void applyStatusFilter(int f);
void applyLabelFilterAll();
void applyLabelFilter(QString label);
void previewFile(QString filePath);
void removeLabelFromRows(QString label);
void renameSelectedTorrent();
protected:
int getRowFromHash(QString hash) const;
QString getHashFromRow(int row) const;
QModelIndex mapToSource(const QModelIndex &index) const;
QModelIndex mapFromSource(const QModelIndex &index) const;
void saveSettings();
bool loadSettings();
QStringList getSelectedTorrentsHashes() const;
int getRowFromHash(QString hash) const;
QString getHashFromRow(int row) const;
QModelIndex mapToSource(const QModelIndex &index) const;
QModelIndex mapFromSource(const QModelIndex &index) const;
void saveSettings();
bool loadSettings();
QStringList getSelectedTorrentsHashes() const;
protected slots:
void torrentDoubleClicked(const QModelIndex& index);
void displayListMenu(const QPoint&);
void currentChanged(const QModelIndex& current, const QModelIndex&);
void toggleSelectedTorrentsSuperSeeding() const;
void toggleSelectedTorrentsSequentialDownload() const;
void toggleSelectedFirstLastPiecePrio() const;
void askNewLabelForSelection();
void torrentDoubleClicked(const QModelIndex& index);
void displayListMenu(const QPoint&);
void currentChanged(const QModelIndex& current, const QModelIndex&);
void toggleSelectedTorrentsSuperSeeding() const;
void toggleSelectedTorrentsSequentialDownload() const;
void toggleSelectedFirstLastPiecePrio() const;
void askNewLabelForSelection();
private:
bool openUrl(const QString& _path) const;
bool openUrl(const QString& _path) const;
signals:
void currentTorrentChanged(const QTorrentHandle &h);
void currentTorrentChanged(const QTorrentHandle &h);
private:
TransferListDelegate *listDelegate;
TorrentModel *listModel;
TransferListSortModel *nameFilterModel;
QBtSession* BTSession;
MainWindow *main_window;
QShortcut *editHotkey;
QShortcut *deleteHotkey;
TransferListDelegate *listDelegate;
TorrentModel *listModel;
TransferListSortModel *nameFilterModel;
QBtSession* BTSession;
MainWindow *main_window;
QShortcut *editHotkey;
QShortcut *deleteHotkey;
};
#endif // TRANSFERLISTWIDGET_H

123
src/webui/abstractrequesthandler.cpp

@ -36,145 +36,134 @@ @@ -36,145 +36,134 @@
#include "abstractrequesthandler.h"
AbstractRequestHandler::AbstractRequestHandler(const HttpRequest &request, const HttpEnvironment &env, WebApplication *app)
: app_(app), session_(0), request_(request), env_(env)
: app_(app), session_(0), request_(request), env_(env)
{
sessionInitialize();
if (!sessionActive() && !isAuthNeeded())
sessionStart();
sessionInitialize();
if (!sessionActive() && !isAuthNeeded())
sessionStart();
}
HttpResponse AbstractRequestHandler::run()
{
response_ = HttpResponse();
response_ = HttpResponse();
if (isBanned())
{
status(403, "Forbidden");
print(QObject::tr("Your IP address has been banned after too many failed authentication attempts."), CONTENT_TYPE_TXT);
}
else
{
processRequest();
}
if (isBanned()) {
status(403, "Forbidden");
print(QObject::tr("Your IP address has been banned after too many failed authentication attempts."), CONTENT_TYPE_TXT);
}
else {
processRequest();
}
return response_;
return response_;
}
bool AbstractRequestHandler::isAuthNeeded()
{
return
(
return
(
env_.clientAddress != QHostAddress::LocalHost &&
env_.clientAddress != QHostAddress::LocalHostIPv6
) || Preferences::instance()->isWebUiLocalAuthEnabled();
) || Preferences::instance()->isWebUiLocalAuthEnabled();
}
void AbstractRequestHandler::status(uint code, const QString& text)
{
response_.status = HttpResponseStatus(code, text);
response_.status = HttpResponseStatus(code, text);
}
void AbstractRequestHandler::header(const QString& name, const QString& value)
{
response_.headers[name] = value;
response_.headers[name] = value;
}
void AbstractRequestHandler::print(const QString& text, const QString& type)
{
print_impl(text.toUtf8(), type);
print_impl(text.toUtf8(), type);
}
void AbstractRequestHandler::print(const QByteArray& data, const QString& type)
{
print_impl(data, type);
print_impl(data, type);
}
void AbstractRequestHandler::print_impl(const QByteArray& data, const QString& type)
{
if (!response_.headers.contains(HEADER_CONTENT_TYPE))
response_.headers[HEADER_CONTENT_TYPE] = type;
if (!response_.headers.contains(HEADER_CONTENT_TYPE))
response_.headers[HEADER_CONTENT_TYPE] = type;
if (type.indexOf("image") > -1)
response_.headers[HEADER_CACHE_CONTROL] = "max-age=3000000";
response_.content += data;
response_.content += data;
}
void AbstractRequestHandler::printFile(const QString& path)
{
QByteArray data;
QString type;
QByteArray data;
QString type;
if (!app_->readFile(path, data, type))
{
status(404, "Not Found");
return;
}
if (!app_->readFile(path, data, type)) {
status(404, "Not Found");
return;
}
print(data, type);
print(data, type);
}
void AbstractRequestHandler::sessionInitialize()
{
app_->sessionInitialize(this);
app_->sessionInitialize(this);
}
void AbstractRequestHandler::sessionStart()
{
if (app_->sessionStart(this))
{
QNetworkCookie cookie(C_SID.toUtf8(), session_->id.toUtf8());
cookie.setPath("/");
header(HEADER_SET_COOKIE, cookie.toRawForm());
}
if (app_->sessionStart(this)) {
QNetworkCookie cookie(C_SID.toUtf8(), session_->id.toUtf8());
cookie.setPath("/");
header(HEADER_SET_COOKIE, cookie.toRawForm());
}
}
void AbstractRequestHandler::sessionEnd()
{
if (sessionActive())
{
QNetworkCookie cookie(C_SID.toUtf8(), session_->id.toUtf8());
cookie.setPath("/");
cookie.setExpirationDate(QDateTime::currentDateTime());
if (sessionActive()) {
QNetworkCookie cookie(C_SID.toUtf8(), session_->id.toUtf8());
cookie.setPath("/");
cookie.setExpirationDate(QDateTime::currentDateTime());
if (app_->sessionEnd(this))
{
header(HEADER_SET_COOKIE, cookie.toRawForm());
if (app_->sessionEnd(this))
header(HEADER_SET_COOKIE, cookie.toRawForm());
}
}
}
bool AbstractRequestHandler::isBanned() const
{
return app_->isBanned(this);
return app_->isBanned(this);
}
int AbstractRequestHandler::failedAttempts() const
{
return app_->failedAttempts(this);
return app_->failedAttempts(this);
}
void AbstractRequestHandler::resetFailedAttempts()
{
app_->resetFailedAttempts(this);
app_->resetFailedAttempts(this);
}
void AbstractRequestHandler::increaseFailedAttempts()
{
app_->increaseFailedAttempts(this);
app_->increaseFailedAttempts(this);
}
QString AbstractRequestHandler::saveTmpFile(const QByteArray &data)
{
QTemporaryFile tmpfile(QDir::temp().absoluteFilePath("qBT-XXXXXX.torrent"));
tmpfile.setAutoRemove(false);
if (tmpfile.open())
{
tmpfile.write(data);
tmpfile.close();
return tmpfile.fileName();
}
qWarning() << "I/O Error: Could not create temporary file";
return QString();
QTemporaryFile tmpfile(QDir::temp().absoluteFilePath("qBT-XXXXXX.torrent"));
tmpfile.setAutoRemove(false);
if (tmpfile.open()) {
tmpfile.write(data);
tmpfile.close();
return tmpfile.fileName();
}
qWarning() << "I/O Error: Could not create temporary file";
return QString();
}

33
src/webui/btjson.cpp

@ -55,7 +55,7 @@ using namespace libtorrent; @@ -55,7 +55,7 @@ using namespace libtorrent;
static QElapsedTimer cacheTimer; \
static bool initialized = false; \
if (initialized && !cacheTimer.hasExpired(DUR)) \
return json::toJson(VAR); \
return json::toJson(VAR); \
initialized = true; \
cacheTimer.start(); \
VAR = VARTYPE()
@ -65,7 +65,7 @@ using namespace libtorrent; @@ -65,7 +65,7 @@ using namespace libtorrent;
static QString prev_hash; \
static QElapsedTimer cacheTimer; \
if (prev_hash == HASH && !cacheTimer.hasExpired(DUR)) \
return json::toJson(VAR); \
return json::toJson(VAR); \
prev_hash = HASH; \
cacheTimer.start(); \
VAR = VARTYPE()
@ -98,6 +98,8 @@ static const char KEY_TORRENT_NUM_INCOMPLETE[] = "num_incomplete"; @@ -98,6 +98,8 @@ static const char KEY_TORRENT_NUM_INCOMPLETE[] = "num_incomplete";
static const char KEY_TORRENT_RATIO[] = "ratio";
static const char KEY_TORRENT_ETA[] = "eta";
static const char KEY_TORRENT_STATE[] = "state";
static const char KEY_TORRENT_SEQUENTIAL_DOWNLOAD[] = "seq_dl";
static const char KEY_TORRENT_FIRST_LAST_PIECE_PRIO[] = "f_l_piece_prio";
// Tracker keys
static const char KEY_TRACKER_URL[] = "url";
@ -157,26 +159,26 @@ public: @@ -157,26 +159,26 @@ public:
switch (type_) {
case QVariant::Int:
return greaterThan_ ? torrent1.toMap().value(key_).toInt() > torrent2.toMap().value(key_).toInt()
: torrent1.toMap().value(key_).toInt() < torrent2.toMap().value(key_).toInt();
: torrent1.toMap().value(key_).toInt() < torrent2.toMap().value(key_).toInt();
case QVariant::LongLong:
return greaterThan_ ? torrent1.toMap().value(key_).toLongLong() > torrent2.toMap().value(key_).toLongLong()
: torrent1.toMap().value(key_).toLongLong() < torrent2.toMap().value(key_).toLongLong();
: torrent1.toMap().value(key_).toLongLong() < torrent2.toMap().value(key_).toLongLong();
case QVariant::ULongLong:
return greaterThan_ ? torrent1.toMap().value(key_).toULongLong() > torrent2.toMap().value(key_).toULongLong()
: torrent1.toMap().value(key_).toULongLong() < torrent2.toMap().value(key_).toULongLong();
: torrent1.toMap().value(key_).toULongLong() < torrent2.toMap().value(key_).toULongLong();
case QMetaType::Float:
return greaterThan_ ? torrent1.toMap().value(key_).toFloat() > torrent2.toMap().value(key_).toFloat()
: torrent1.toMap().value(key_).toFloat() < torrent2.toMap().value(key_).toFloat();
: torrent1.toMap().value(key_).toFloat() < torrent2.toMap().value(key_).toFloat();
case QVariant::Double:
return greaterThan_ ? torrent1.toMap().value(key_).toDouble() > torrent2.toMap().value(key_).toDouble()
: torrent1.toMap().value(key_).toDouble() < torrent2.toMap().value(key_).toDouble();
: torrent1.toMap().value(key_).toDouble() < torrent2.toMap().value(key_).toDouble();
default:
return greaterThan_ ? torrent1.toMap().value(key_).toString() > torrent2.toMap().value(key_).toString()
: torrent1.toMap().value(key_).toString() < torrent2.toMap().value(key_).toString();
: torrent1.toMap().value(key_).toString() < torrent2.toMap().value(key_).toString();
}
#else
return greaterThan_ ? torrent1.toMap().value(key_) > torrent2.toMap().value(key_)
: torrent1.toMap().value(key_) < torrent2.toMap().value(key_);
: torrent1.toMap().value(key_) < torrent2.toMap().value(key_);
#endif
}
@ -211,6 +213,12 @@ static QVariantMap toMap(const QTorrentHandle& h) @@ -211,6 +213,12 @@ static QVariantMap toMap(const QTorrentHandle& h)
ret[KEY_TORRENT_RATIO] = (ratio > 100.) ? -1 : ratio;
ret[KEY_TORRENT_STATE] = h.torrentState().toString();
ret[KEY_TORRENT_ETA] = h.eta();
if (h.has_metadata()) {
if (status.sequential_download)
ret[KEY_TORRENT_SEQUENTIAL_DOWNLOAD] = true;
if (h.first_last_piece_first())
ret[KEY_TORRENT_FIRST_LAST_PIECE_PRIO] = true;
}
return ret;
}
@ -236,7 +244,7 @@ static QVariantMap toMap(const QTorrentHandle& h) @@ -236,7 +244,7 @@ static QVariantMap toMap(const QTorrentHandle& h)
* - "state": Torrent state
*/
QByteArray btjson::getTorrents(QString filter, QString label,
QString sortedColumn, bool reverse, int limit, int offset)
QString sortedColumn, bool reverse, int limit, int offset)
{
QVariantList torrent_list;
@ -245,7 +253,7 @@ QByteArray btjson::getTorrents(QString filter, QString label, @@ -245,7 +253,7 @@ QByteArray btjson::getTorrents(QString filter, QString label,
std::vector<torrent_handle>::const_iterator end = torrents.end();
QTorrentFilter torrentFilter(filter, label);
for( ; it != end; ++it) {
for(; it != end; ++it) {
QTorrentHandle torrent = QTorrentHandle(*it);
if (torrentFilter.apply(torrent))
@ -294,8 +302,9 @@ QByteArray btjson::getTrackersForTorrent(const QString& hash) @@ -294,8 +302,9 @@ QByteArray btjson::getTrackersForTorrent(const QString& hash)
tracker_dict[KEY_TRACKER_URL] = tracker_url;
const TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url));
QString status;
if (it->verified)
if (it->verified) {
status = tr("Working");
}
else {
if (it->updating && it->fails == 0)
status = tr("Updating...");

29
src/webui/requesthandler.cpp

@ -62,6 +62,7 @@ const QString SCOPE_THEME = "theme"; @@ -62,6 +62,7 @@ const QString SCOPE_THEME = "theme";
const QString DEFAULT_ACTION = "index";
const QString WEBUI_ACTION = "webui";
const QString VERSION_INFO = "version";
const QString MAX_AGE_MONTH = "public, max-age=2592000";
#define ADD_ACTION(scope, action) actions[#scope][#action] = &RequestHandler::action_##scope##_##action
@ -99,6 +100,8 @@ QMap<QString, QMap<QString, RequestHandler::Action> > RequestHandler::initialize @@ -99,6 +100,8 @@ QMap<QString, QMap<QString, RequestHandler::Action> > RequestHandler::initialize
ADD_ACTION(command, getTorrentDlLimit);
ADD_ACTION(command, setTorrentUpLimit);
ADD_ACTION(command, setTorrentDlLimit);
ADD_ACTION(command, toggleSequentialDownload);
ADD_ACTION(command, toggleFirstLastPiecePrio);
ADD_ACTION(command, delete);
ADD_ACTION(command, deletePerm);
ADD_ACTION(command, increasePrio);
@ -178,12 +181,14 @@ void RequestHandler::action_public_theme() @@ -178,12 +181,14 @@ void RequestHandler::action_public_theme()
qDebug() << Q_FUNC_INFO << "There icon:" << url;
printFile(url);
header(HEADER_CACHE_CONTROL, MAX_AGE_MONTH);
}
void RequestHandler::action_public_images()
{
const QString path = ":/Icons/" + args_.join("/");
printFile(path);
header(HEADER_CACHE_CONTROL, MAX_AGE_MONTH);
}
// GET params:
@ -423,6 +428,30 @@ void RequestHandler::action_command_setTorrentDlLimit() @@ -423,6 +428,30 @@ void RequestHandler::action_command_setTorrentDlLimit()
h.set_download_limit(limit);
}
void RequestHandler::action_command_toggleSequentialDownload()
{
QStringList hashes = request().posts["hashes"].split("|");
foreach (const QString &hash, hashes) {
try {
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
h.toggleSequentialDownload();
}
catch(invalid_handle&) {}
}
}
void RequestHandler::action_command_toggleFirstLastPiecePrio()
{
QStringList hashes = request().posts["hashes"].split("|");
foreach (const QString &hash, hashes) {
try {
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
h.toggleFirstLastPiecePrio();
}
catch(invalid_handle&) {}
}
}
void RequestHandler::action_command_delete()
{
QStringList hashes = request().posts["hashes"].split("|");

2
src/webui/requesthandler.h

@ -74,6 +74,8 @@ private: @@ -74,6 +74,8 @@ private:
void action_command_getTorrentDlLimit();
void action_command_setTorrentUpLimit();
void action_command_setTorrentDlLimit();
void action_command_toggleSequentialDownload();
void action_command_toggleFirstLastPiecePrio();
void action_command_delete();
void action_command_deletePerm();
void action_command_increasePrio();

231
src/webui/www/private/index.html

@ -1,120 +1,125 @@ @@ -1,120 +1,125 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=10; IE=9; IE=8;" />
<title>qBittorrent web User Interface</title>
<link rel="stylesheet" href="css/dynamicTable.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="css/style.css" />
<!--<link rel="stylesheet" type="text/css" href="css/Content.css" />-->
<link rel="stylesheet" type="text/css" href="css/Core.css" />
<link rel="stylesheet" type="text/css" href="css/Layout.css" />
<link rel="stylesheet" type="text/css" href="css/Window.css" />
<link rel="stylesheet" type="text/css" href="css/Tabs.css" />
<script type="text/javascript" src="scripts/mootools-1.2-core-yc.js" charset="utf-8"></script>
<script type="text/javascript" src="scripts/mootools-1.2-more.js" charset="utf-8"></script>
<!--[if IE]>
<script type="text/javascript" src="scripts/excanvas-compressed.js"></script>
<![endif]-->
<script type="text/javascript" src="scripts/mocha-yc.js"></script>
<script type="text/javascript" src="scripts/mocha-init.js"></script>
<script type="text/javascript" src="scripts/misc.js"></script>
<script type="text/javascript" src="scripts/progressbar.js"></script>
<script type="text/javascript" src="scripts/dynamicTable.js" charset="utf-8"></script>
<script type="text/javascript" src="scripts/client.js" charset="utf-8"></script>
<script type="text/javascript" src="scripts/contextmenu.js" charset="utf-8"></script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=10; IE=9; IE=8;" />
<title>qBittorrent web User Interface</title>
<link rel="stylesheet" href="css/dynamicTable.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="css/style.css" />
<!--<link rel="stylesheet" type="text/css" href="css/Content.css" />-->
<link rel="stylesheet" type="text/css" href="css/Core.css" />
<link rel="stylesheet" type="text/css" href="css/Layout.css" />
<link rel="stylesheet" type="text/css" href="css/Window.css" />
<link rel="stylesheet" type="text/css" href="css/Tabs.css" />
<script type="text/javascript" src="scripts/mootools-1.2-core-yc.js" charset="utf-8"></script>
<script type="text/javascript" src="scripts/mootools-1.2-more.js" charset="utf-8"></script>
<!--[if IE]>
<script type="text/javascript" src="scripts/excanvas-compressed.js"></script>
<![endif]-->
<script type="text/javascript" src="scripts/mocha-yc.js"></script>
<script type="text/javascript" src="scripts/mocha-init.js"></script>
<script type="text/javascript" src="scripts/misc.js"></script>
<script type="text/javascript" src="scripts/progressbar.js"></script>
<script type="text/javascript" src="scripts/dynamicTable.js" charset="utf-8"></script>
<script type="text/javascript" src="scripts/client.js" charset="utf-8"></script>
<script type="text/javascript" src="scripts/contextmenu.js" charset="utf-8"></script>
</head>
<body>
<div id="desktop">
<div id="desktopHeader">
<!--<div id="desktopTitlebar">
<h1 class="applicationTitle">qBittorrent Web User Interface <span class="version">version 2.0.0</span></h1>
</div>-->
<div id="desktopNavbar">
<ul>
<li>
<a class="returnFalse">_(File)</a>
<ul>
<li><a id="uploadLink"><img class="MyMenuIcon" alt="_(&Add torrent file...)" src="theme/list-add" width="16" height="16" onload="fixPNG(this)"/>_(&Add torrent file...)</a></li>
<li><a id="downloadLink"><img class="MyMenuIcon" alt="_(Add &link to torrent...)" src="theme/insert-link" width="16" height="16" onload="fixPNG(this)"/>_(Add &link to torrent...)</a></li>
<li class="divider"><a id="logoutLink"><img class="MyMenuIcon" alt="_(Logout)" src="theme/system-log-out" width="16" height="16" onload="fixPNG(this)"/>_(Logout)</a></li>
<li><a id="shutdownLink"><img class="MyMenuIcon" alt="_(Exit qBittorrent)" src="theme/application-exit" width="16" height="16" onload="fixPNG(this)"/>_(Exit qBittorrent)</a></li>
</ul>
</li>
<li>
<a class="returnFalse">_(Edit)</a>
<ul>
<li><a id="resumeAllLink"><img class="MyMenuIcon" alt="_(R&esume All)" src="theme/media-playback-start" width="16" height="16" onload="fixPNG(this)"/>_(R&esume All)</a></li>
<li><a id="pauseAllLink"><img class="MyMenuIcon" alt="_(P&ause All)" src="theme/media-playback-pause" width="16" height="16" onload="fixPNG(this)"/>_(P&ause All)</a></li>
<li class="divider"><a id="resumeLink"><img class="MyMenuIcon" alt="_(&Resume)" src="theme/media-playback-start" width="16" height="16" onload="fixPNG(this)"/>_(&Resume)</a></li>
<li><a id="pauseLink"><img class="MyMenuIcon" src="theme/media-playback-pause" alt="_(&Pause)" width="16" height="16" onload="fixPNG(this)"/>_(&Pause)</a></li>
<li><a id="recheckLink"><img class="MyMenuIcon" src="theme/document-edit-verify" alt="_(Force recheck)" width="16" height="16" onload="fixPNG(this)"/>_(Force recheck)</a></li>
<li class="divider"><a id="deleteLink"><img class="MyMenuIcon" src="theme/list-remove" alt="_(&Delete)" width="16" height="16" onload="fixPNG(this)"/>_(&Delete)</a></li>
</ul>
</li>
<li>
<a class="returnFalse">_(&View)</a>
<ul>
<li><a id="speedInBrowserTitleBarLink"><img class="MyMenuIcon" src="theme/checked" alt="_(&Speed in title bar)" width="16" height="16" onload="fixPNG(this)"/>_(&Speed in title bar)</a></li>
</ul>
</li>
<li>
<a class="returnFalse">_(&Tools)</a>
<ul>
<li><a id="preferencesLink"><img class="MyMenuIcon" src="theme/preferences-system" alt="_(&Options...)" width="16" height="16" onload="fixPNG(this)"/>_(&Options...)</a></li>
</ul>
</li>
<li>
<a class="returnFalse">_(&Help)</a>
<ul>
<li><a id="bugLink" target="_blank" href="http://bugs.qbittorrent.org/"><img class="MyMenuIcon" src="theme/tools-report-bug" alt="_(Report a &bug)" width="16" height="16" onload="fixPNG(this)"/>_(Report a &bug)</a></li>
<li><a id="siteLink" target="_blank" href="http://www.qbittorrent.org/"><img class="MyMenuIcon" src="images/skin/qbittorrent16.png" alt="_(Visit &Website)" width="16" height="16" onload="fixPNG(this)"/>_(Visit &Website)</a></li>
<li><a id="docsLink" target="_blank" href="http://wiki.qbittorrent.org/"><img class="MyMenuIcon" src="theme/help-contents" alt="_(&Documentation)" width="16" height="16" onload="fixPNG(this)"/>_(&Documentation)</a></li>
<li><a id="aboutLink"><img class="MyMenuIcon" src="theme/help-about" alt="_(&About)" width="16" height="16" onload="fixPNG(this)"/>_(&About)</a></li>
</ul>
</li>
</ul>
</div>
<div id="mochaToolbar">
&nbsp;&nbsp;
<a id="uploadButton"><img class="mochaToolButton" title="_(&Add torrent file...)" src="theme/list-add" alt="_(&Add torrent file...)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="downloadButton"><img class="mochaToolButton" title="_(Add &link to torrent...)" src="theme/insert-link" alt="_(Add &link to torrent...)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="deleteButton" class="divider"><img class="mochaToolButton" title="_(Delete)" src="theme/list-remove" alt="_(Delete)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="resumeButton" class="divider"><img class="mochaToolButton" title="_(Resume)" src="theme/media-playback-start" alt="_(Resume)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="pauseButton"><img class="mochaToolButton" title="_(Pause)" src="theme/media-playback-pause" alt="_(Pause)" width="24" height="24" onload="fixPNG(this)"/></a>
<span id="queueingButtons">
<a id="decreasePrioButton" class="divider"><img class="mochaToolButton" title="_(Decrease priority)" src="theme/go-down" alt="_(Decrease priority)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="increasePrioButton"><img class="mochaToolButton" title="_(Increase priority)" src="theme/go-up" alt="_(Increase priority)" width="24" height="24" onload="fixPNG(this)"/></a>
</span>
<a id="preferencesButton" class="divider"><img class="mochaToolButton" title="_(Options)" src="theme/preferences-system" alt="_(Options)" width="24" height="24" onload="fixPNG(this)"/></a>
</div>
</div>
<div id="pageWrapper">
</div>
</div>
<ul id="contextmenu">
<li><a href="#Start"><img src="theme/media-playback-start" alt="_(Resume)"/> _(Resume)</a></li>
<li><a href="#Pause"><img src="theme/media-playback-pause" alt="_(Pause)"/> _(Pause)</a></li>
<li class="separator"><a href="#Delete"><img src="theme/list-remove" alt="_(Delete)"/> _(Delete)</a></li>
<li class="separator"><a href="#priority" class="arrow-right">_(Priority)</a>
<ul>
<li><a href="#prioTop"><img src="theme/go-top" alt="_(Move to top)"/> _(Move to top)</a></li>
<li><a href="#prioUp"><img src="theme/go-up" alt="_(Move up)"/> _(Move up)</a></li>
<li><a href="#prioDown"><img src="theme/go-down" alt="_(Move down)"/> _(Move down)</a></li>
<li><a href="#prioBottom"><img src="theme/go-bottom" alt="_(Move to bottom)"/> _(Move to bottom)</a></li>
</ul>
</li>
<li class="separator"><a href="#DownloadLimit"><img src="images/skin/download.png" alt="_(Limit download rate...)"/> _(Limit download rate...)</a></li>
<li><a href="#UploadLimit"><img src="images/skin/seeding.png" alt="_(Limit upload rate...)"/> _(Limit upload rate...)</a></li>
<li class="separator"><a href="#ForceRecheck"><img src="theme/document-edit-verify" alt="_(Force recheck)"/> _(Force recheck)</a></li>
</ul>
<div id="desktopFooterWrapper">
<div id="desktopFooter">
<span id="error_div"></span>
<table style="position: absolute; right: 5px;">
<tr><td id="DlInfos" style="cursor:pointer;"></td><td style="width: 2px;margin:0;"><img src="images/skin/toolbox-divider.gif" alt="" style="height: 18px; padding-left: 10px; padding-right: 10px; margin-bottom: -2px;"/></td><td id="UpInfos" style="cursor:pointer;"></td></tr>
</table>
</div>
</div>
<div id="desktop">
<div id="desktopHeader">
<!--<div id="desktopTitlebar">
<h1 class="applicationTitle">qBittorrent Web User Interface <span class="version">version 2.0.0</span></h1>
</div>-->
<div id="desktopNavbar">
<ul>
<li>
<a class="returnFalse">_(File)</a>
<ul>
<li><a id="uploadLink"><img class="MyMenuIcon" alt="_(&Add torrent file...)" src="theme/list-add" width="16" height="16" onload="fixPNG(this)"/>_(&Add torrent file...)</a></li>
<li><a id="downloadLink"><img class="MyMenuIcon" alt="_(Add &link to torrent...)" src="theme/insert-link" width="16" height="16" onload="fixPNG(this)"/>_(Add &link to torrent...)</a></li>
<li class="divider"><a id="logoutLink"><img class="MyMenuIcon" alt="_(Logout)" src="theme/system-log-out" width="16" height="16" onload="fixPNG(this)"/>_(Logout)</a></li>
<li><a id="shutdownLink"><img class="MyMenuIcon" alt="_(Exit qBittorrent)" src="theme/application-exit" width="16" height="16" onload="fixPNG(this)"/>_(Exit qBittorrent)</a></li>
</ul>
</li>
<li>
<a class="returnFalse">_(Edit)</a>
<ul>
<li><a id="resumeAllLink"><img class="MyMenuIcon" alt="_(R&esume All)" src="theme/media-playback-start" width="16" height="16" onload="fixPNG(this)"/>_(R&esume All)</a></li>
<li><a id="pauseAllLink"><img class="MyMenuIcon" alt="_(P&ause All)" src="theme/media-playback-pause" width="16" height="16" onload="fixPNG(this)"/>_(P&ause All)</a></li>
<li class="divider"><a id="resumeLink"><img class="MyMenuIcon" alt="_(&Resume)" src="theme/media-playback-start" width="16" height="16" onload="fixPNG(this)"/>_(&Resume)</a></li>
<li><a id="pauseLink"><img class="MyMenuIcon" src="theme/media-playback-pause" alt="_(&Pause)" width="16" height="16" onload="fixPNG(this)"/>_(&Pause)</a></li>
<li><a id="recheckLink"><img class="MyMenuIcon" src="theme/document-edit-verify" alt="_(Force recheck)" width="16" height="16" onload="fixPNG(this)"/>_(Force recheck)</a></li>
<li class="divider"><a id="deleteLink"><img class="MyMenuIcon" src="theme/list-remove" alt="_(&Delete)" width="16" height="16" onload="fixPNG(this)"/>_(&Delete)</a></li>
</ul>
</li>
<li>
<a class="returnFalse">_(&View)</a>
<ul>
<li><a id="speedInBrowserTitleBarLink"><img class="MyMenuIcon" src="theme/checked" alt="_(&Speed in title bar)" width="16" height="16" onload="fixPNG(this)"/>_(&Speed in title bar)</a></li>
</ul>
</li>
<li>
<a class="returnFalse">_(&Tools)</a>
<ul>
<li><a id="preferencesLink"><img class="MyMenuIcon" src="theme/preferences-system" alt="_(&Options...)" width="16" height="16" onload="fixPNG(this)"/>_(&Options...)</a></li>
</ul>
</li>
<li>
<a class="returnFalse">_(&Help)</a>
<ul>
<li><a id="bugLink" target="_blank" href="http://bugs.qbittorrent.org/"><img class="MyMenuIcon" src="theme/tools-report-bug" alt="_(Report a &bug)" width="16" height="16" onload="fixPNG(this)"/>_(Report a &bug)</a></li>
<li><a id="siteLink" target="_blank" href="http://www.qbittorrent.org/"><img class="MyMenuIcon" src="images/skin/qbittorrent16.png" alt="_(Visit &Website)" width="16" height="16" onload="fixPNG(this)"/>_(Visit &Website)</a></li>
<li><a id="docsLink" target="_blank" href="http://wiki.qbittorrent.org/"><img class="MyMenuIcon" src="theme/help-contents" alt="_(&Documentation)" width="16" height="16" onload="fixPNG(this)"/>_(&Documentation)</a></li>
<li><a id="aboutLink"><img class="MyMenuIcon" src="theme/help-about" alt="_(&About)" width="16" height="16" onload="fixPNG(this)"/>_(&About)</a></li>
</ul>
</li>
</ul>
</div>
<div id="mochaToolbar">
&nbsp;&nbsp;
<a id="uploadButton"><img class="mochaToolButton" title="_(&Add torrent file...)" src="theme/list-add" alt="_(&Add torrent file...)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="downloadButton"><img class="mochaToolButton" title="_(Add &link to torrent...)" src="theme/insert-link" alt="_(Add &link to torrent...)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="deleteButton" class="divider"><img class="mochaToolButton" title="_(Delete)" src="theme/list-remove" alt="_(Delete)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="resumeButton" class="divider"><img class="mochaToolButton" title="_(Resume)" src="theme/media-playback-start" alt="_(Resume)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="pauseButton"><img class="mochaToolButton" title="_(Pause)" src="theme/media-playback-pause" alt="_(Pause)" width="24" height="24" onload="fixPNG(this)"/></a>
<span id="queueingButtons">
<a id="bottomPrioButton" class="divider"><img class="mochaToolButton" title="_(Move to bottom)" src="theme/go-bottom" alt="_(Move to bottom)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="decreasePrioButton"><img class="mochaToolButton" title="_(Decrease priority)" src="theme/go-down" alt="_(Decrease priority)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="increasePrioButton"><img class="mochaToolButton" title="_(Increase priority)" src="theme/go-up" alt="_(Increase priority)" width="24" height="24" onload="fixPNG(this)"/></a>
<a id="topPrioButton"><img class="mochaToolButton" title="_(Move to top)" src="theme/go-top" alt="_(Move to top)" width="24" height="24" onload="fixPNG(this)"/></a>
</span>
<a id="preferencesButton" class="divider"><img class="mochaToolButton" title="_(Options)" src="theme/preferences-system" alt="_(Options)" width="24" height="24" onload="fixPNG(this)"/></a>
</div>
</div>
<div id="pageWrapper">
</div>
</div>
<ul id="contextmenu">
<li><a href="#Start"><img src="theme/media-playback-start" alt="_(Resume)"/> _(Resume)</a></li>
<li><a href="#Pause"><img src="theme/media-playback-pause" alt="_(Pause)"/> _(Pause)</a></li>
<li class="separator"><a href="#Delete"><img src="theme/list-remove" alt="_(Delete)"/> _(Delete)</a></li>
<li id="queueingMenuItems" class="separator">
<a href="#priority" class="arrow-right"><span style="display: inline-block; width:16px"></span> _(Priority)</a>
<ul>
<li><a href="#prioTop"><img src="theme/go-top" alt="_(Move to top)"/> _(Move to top)</a></li>
<li><a href="#prioUp"><img src="theme/go-up" alt="_(Move up)"/> _(Move up)</a></li>
<li><a href="#prioDown"><img src="theme/go-down" alt="_(Move down)"/> _(Move down)</a></li>
<li><a href="#prioBottom"><img src="theme/go-bottom" alt="_(Move to bottom)"/> _(Move to bottom)</a></li>
</ul>
</li>
<li class="separator"><a href="#DownloadLimit"><img src="images/skin/download.png" alt="_(Limit download rate...)"/> _(Limit download rate...)</a></li>
<li><a href="#UploadLimit"><img src="images/skin/seeding.png" alt="_(Limit upload rate...)"/> _(Limit upload rate...)</a></li>
<li class="separator"><a href="#SequentialDownload"><img src="theme/checked" alt="_(Download in sequential order)"/> _(Download in sequential order)</a></li>
<li><a href="#FirstLastPiecePrio"><img src="theme/checked" alt="_(Download first and last piece first)"/> _(Download first and last piece first)</a></li>
<li class="separator"><a href="#ForceRecheck"><img src="theme/document-edit-verify" alt="_(Force recheck)"/> _(Force recheck)</a></li>
</ul>
<div id="desktopFooterWrapper">
<div id="desktopFooter">
<span id="error_div"></span>
<table style="position: absolute; right: 5px;">
<tr><td id="DlInfos" style="cursor:pointer;"></td><td style="width: 2px;margin:0;"><img src="images/skin/toolbox-divider.gif" alt="" style="height: 18px; padding-left: 10px; padding-right: 10px; margin-bottom: -2px;"/></td><td id="UpInfos" style="cursor:pointer;"></td></tr>
</table>
</div>
</div>
</body>
</html>

25
src/webui/www/public/filters.html

@ -1,17 +1,8 @@ @@ -1,17 +1,8 @@
<ul class="filterList">
<li id="all_filter"><a href="#" onclick="setFilter('all');"><img src="images/skin/filterall.png"/>_(All)</a></li>
<li id="downloading_filter"><a href="#" onclick="setFilter('downloading');"><img src="images/skin/downloading.png"/>_(Downloading)</a></li>
<li id="completed_filter"><a href="#" onclick="setFilter('completed');"><img src="images/skin/uploading.png"/>_(Completed)</a></li>
<li id="paused_filter"><a href="#" onclick="setFilter('paused');"><img src="images/skin/paused.png"/>_(Paused)</a></li>
<li id="active_filter"><a href="#" onclick="setFilter('active');"><img src="images/skin/filteractive.png"/>_(Active)</a></li>
<li id="inactive_filter"><a href="#" onclick="setFilter('inactive');"><img src="images/skin/filterinactive.png"/>_(Inactive)</a></li>
</ul>
<script type="text/javascript">
// Remember this via Cookie
var filter = Cookie.read('selected_filter');
if(!$defined(last_filter)) {
filter = 'all';
}
$(filter+'_filter').addClass('selectedFilter');
</script>
<ul class="filterList">
<li id="all_filter"><a href="#" onclick="setFilter('all');"><img src="images/skin/filterall.png"/>_(All)</a></li>
<li id="downloading_filter"><a href="#" onclick="setFilter('downloading');"><img src="images/skin/downloading.png"/>_(Downloading)</a></li>
<li id="completed_filter"><a href="#" onclick="setFilter('completed');"><img src="images/skin/uploading.png"/>_(Completed)</a></li>
<li id="paused_filter"><a href="#" onclick="setFilter('paused');"><img src="images/skin/paused.png"/>_(Paused)</a></li>
<li id="active_filter"><a href="#" onclick="setFilter('active');"><img src="images/skin/filteractive.png"/>_(Active)</a></li>
<li id="inactive_filter"><a href="#" onclick="setFilter('inactive');"><img src="images/skin/filterinactive.png"/>_(Inactive)</a></li>
</ul>

269
src/webui/www/public/scripts/client.js

@ -24,6 +24,128 @@ @@ -24,6 +24,128 @@
myTable = new dynamicTable();
var stateToImg = function (state) {
if (state == "pausedUP" || state == "pausedDL") {
state = "paused";
} else {
if (state == "queuedUP" || state == "queuedDL") {
state = "queued";
} else {
if (state == "checkingUP" || state == "checkingDL") {
state = "checking";
}
}
}
return 'images/skin/' + state + '.png';
};
filter = getLocalStorageItem('selected_filter', 'all');
var loadTorrentsInfoTimer;
var loadTorrentsInfo = function () {
var queueing_enabled = false;
var url = new URI('json/torrents');
url.setData('filter', filter);
url.setData('sort', myTable.table.sortedColumn);
url.setData('reverse', myTable.table.reverseSort);
var request = new Request.JSON({
url : url,
noCache : true,
method : 'get',
onFailure : function () {
$('error_div').set('html', '_(qBittorrent client is not reachable)');
loadTorrentsInfoTimer = loadTorrentsInfo.delay(2000);
},
onSuccess : function (events) {
$('error_div').set('html', '');
if (events) {
// Add new torrents or update them
torrent_hashes = myTable.getRowIds();
events_hashes = new Array();
pos = 0;
events.each(function (event) {
events_hashes[events_hashes.length] = event.hash;
var row = new Array();
var data = new Array();
row.length = 10;
row[0] = stateToImg(event.state);
row[1] = event.name;
row[2] = event.priority > -1 ? event.priority : null;
data[2] = event.priority;
row[3] = friendlyUnit(event.size, false);
data[3] = event.size;
row[4] = (event.progress * 100).round(1);
if (row[4] == 100.0 && event.progress != 1.0)
row[4] = 99.9;
data[4] = event.progress;
row[5] = event.num_seeds;
if (event.num_complete != -1)
row[5] += " (" + event.num_complete + ")";
data[5] = event.num_seeds;
row[6] = event.num_leechs;
if (event.num_incomplete != -1)
row[6] += " (" + event.num_incomplete + ")";
data[6] = event.num_leechs;
row[7] = friendlyUnit(event.dlspeed, true);
data[7] = event.dlspeed;
row[8] = friendlyUnit(event.upspeed, true);
data[8] = event.upspeed;
row[9] = friendlyDuration(event.eta);
data[9] = event.eta;
if (event.ratio == -1)
row[10] = "∞";
else
row[10] = (Math.floor(100 * event.ratio) / 100).toFixed(2); //Don't round up
data[10] = event.ratio;
if (row[2] != null)
queueing_enabled = true;
attrs = {};
attrs['downloaded'] = (event.progress == 1.0);
attrs['state'] = event.state;
attrs['seq_dl'] = (event.seq_dl == true);
attrs['f_l_piece_prio'] = (event.f_l_piece_prio == true);
if (!torrent_hashes.contains(event.hash)) {
// New unfinished torrent
torrent_hashes[torrent_hashes.length] = event.hash;
//alert("Inserting row");
myTable.insertRow(event.hash, row, data, attrs, pos);
} else {
// Update torrent data
myTable.updateRow(event.hash, row, data, attrs, pos);
}
pos++;
});
// Remove deleted torrents
torrent_hashes.each(function (hash) {
if (!events_hashes.contains(hash)) {
myTable.removeRow(hash);
}
});
if (queueing_enabled) {
$('queueingButtons').removeClass('invisible');
$('queueingMenuItems').removeClass('invisible');
myTable.showPriority();
} else {
$('queueingButtons').addClass('invisible');
$('queueingMenuItems').addClass('invisible');
myTable.hidePriority();
}
myTable.altRow();
}
loadTorrentsInfoTimer = loadTorrentsInfo.delay(1500);
}
}).send();
};
var updateTransferList = function() {
clearTimeout(loadTorrentsInfoTimer);
loadTorrentsInfoTimer = loadTorrentsInfo();
}
window.addEvent('load', function () {
var saveColumnSizes = function () {
@ -59,6 +181,23 @@ window.addEvent('load', function () { @@ -59,6 +181,23 @@ window.addEvent('load', function () {
resizeLimit : [100, 300]
});
MochaUI.Desktop.setDesktopSize();
setFilter = function (f) {
// Visually Select the right filter
$("all_filter").removeClass("selectedFilter");
$("downloading_filter").removeClass("selectedFilter");
$("completed_filter").removeClass("selectedFilter");
$("paused_filter").removeClass("selectedFilter");
$("active_filter").removeClass("selectedFilter");
$("inactive_filter").removeClass("selectedFilter");
$(f + "_filter").addClass("selectedFilter");
filter = f;
localStorage.setItem('selected_filter', f);
// Reload torrents
if (typeof myTable.table != 'undefined')
updateTransferList();
}
new MochaUI.Panel({
id : 'Filters',
title : 'Panel',
@ -71,6 +210,9 @@ window.addEvent('load', function () { @@ -71,6 +210,9 @@ window.addEvent('load', function () {
},
loadMethod : 'xhr',
contentURL : 'filters.html',
onContentLoaded : function () {
setFilter(filter);
},
column : 'filtersColumn',
height : 300
});
@ -80,21 +222,6 @@ window.addEvent('load', function () { @@ -80,21 +222,6 @@ window.addEvent('load', function () {
if (!speedInTitle)
$('speedInBrowserTitleBarLink').firstChild.style.opacity = '0';
var stateToImg = function (state) {
if (state == "pausedUP" || state == "pausedDL") {
state = "paused";
} else {
if (state == "queuedUP" || state == "queuedDL") {
state = "queued";
} else {
if (state == "checkingUP" || state == "checkingDL") {
state = "checking";
}
}
}
return 'images/skin/' + state + '.png';
};
var loadTransferInfoTimer;
var loadTransferInfo = function () {
var url = 'json/transferInfo';
@ -135,102 +262,6 @@ window.addEvent('load', function () { @@ -135,102 +262,6 @@ window.addEvent('load', function () {
$('DlInfos').addEvent('click', globalDownloadLimitFN);
$('UpInfos').addEvent('click', globalUploadLimitFN);
var ajaxfnTimer;
var ajaxfn = function () {
var queueing_enabled = false;
var url = new URI('json/torrents');
url.setData('filter', filter);
url.setData('sort', myTable.table.sortedColumn);
url.setData('reverse', myTable.table.reverseSort);
var request = new Request.JSON({
url : url,
noCache : true,
method : 'get',
onFailure : function () {
$('error_div').set('html', '_(qBittorrent client is not reachable)');
ajaxfnTimer = ajaxfn.delay(2000);
},
onSuccess : function (events) {
$('error_div').set('html', '');
if (events) {
// Add new torrents or update them
torrent_hashes = myTable.getRowIds();
events_hashes = new Array();
pos = 0;
events.each(function (event) {
events_hashes[events_hashes.length] = event.hash;
var row = new Array();
var data = new Array();
row.length = 10;
row[0] = stateToImg(event.state);
row[1] = event.name;
row[2] = event.priority > -1 ? event.priority : null;
data[2] = event.priority;
row[3] = friendlyUnit(event.size, false);
data[3] = event.size;
row[4] = (event.progress * 100).round(1);
if (row[4] == 100.0 && event.progress != 1.0)
row[4] = 99.9;
data[4] = event.progress;
row[5] = event.num_seeds;
if (event.num_complete != -1)
row[5] += " (" + event.num_complete + ")";
data[5] = event.num_seeds;
row[6] = event.num_leechs;
if (event.num_incomplete != -1)
row[6] += " (" + event.num_incomplete + ")";
data[6] = event.num_leechs;
row[7] = friendlyUnit(event.dlspeed, true);
data[7] = event.dlspeed;
row[8] = friendlyUnit(event.upspeed, true);
data[8] = event.upspeed;
row[9] = friendlyDuration(event.eta);
data[9] = event.eta;
if (event.ratio == -1)
row[10] = "∞";
else
row[10] = (Math.floor(100 * event.ratio) / 100).toFixed(2); //Don't round up
data[10] = event.ratio;
if (row[2] != null)
queueing_enabled = true;
if (!torrent_hashes.contains(event.hash)) {
// New unfinished torrent
torrent_hashes[torrent_hashes.length] = event.hash;
//alert("Inserting row");
myTable.insertRow(event.hash, row, data, event.state, pos);
} else {
// Update torrent data
myTable.updateRow(event.hash, row, data, event.state, pos);
}
pos++;
});
// Remove deleted torrents
torrent_hashes.each(function (hash) {
if (!events_hashes.contains(hash)) {
myTable.removeRow(hash);
}
});
if (queueing_enabled) {
$('queueingButtons').removeClass('invisible');
myTable.showPriority();
} else {
$('queueingButtons').addClass('invisible');
myTable.hidePriority();
}
myTable.altRow();
}
ajaxfnTimer = ajaxfn.delay(1500);
}
}).send();
};
var updateTransferList = function() {
clearTimeout(ajaxfnTimer);
ajaxfnTimer = ajaxfn();
}
setSortedColumn = function (column) {
myTable.setSortedColumn(column);
updateTransferList();
@ -288,22 +319,6 @@ window.addEvent('load', function () { @@ -288,22 +319,6 @@ window.addEvent('load', function () {
column : 'mainColumn',
height : prop_h
});
setFilter = function (f) {
// Visually Select the right filter
$("all_filter").removeClass("selectedFilter");
$("downloading_filter").removeClass("selectedFilter");
$("completed_filter").removeClass("selectedFilter");
$("paused_filter").removeClass("selectedFilter");
$("active_filter").removeClass("selectedFilter");
$("inactive_filter").removeClass("selectedFilter");
$(f + "_filter").addClass("selectedFilter");
filter = f;
localStorage.setItem('selected_filter', f);
// Reload torrents
updateTransferList();
}
});
function closeWindows() {

100
src/webui/www/public/scripts/contextmenu.js

@ -127,9 +127,89 @@ var ContextMenu = new Class({ @@ -127,9 +127,89 @@ var ContextMenu = new Class({
}.bind(this));
},
updateMenuItems: function () {
all_are_seq_dl = true;
there_are_seq_dl = false;
all_are_f_l_piece_prio = true;
there_are_f_l_piece_prio = false;
all_are_downloaded = true;
all_are_paused = true;
there_are_paused = false;
var h = myTable.selectedIds();
h.each(function(item, index){
tr = myTable.rows.get(item);
if (tr.getAttribute('seq_dl') != 'true')
all_are_seq_dl = false;
else
there_are_seq_dl = true;
if (tr.getAttribute('f_l_piece_prio') != 'true')
all_are_f_l_piece_prio = false;
else
there_are_f_l_piece_prio = true;
if (tr.getAttribute('downloaded') != 'true')
all_are_downloaded = false;
state = tr.getAttribute('state');
if ((state != 'pausedUP') && (state != 'pausedDL'))
all_are_paused = false;
else
there_are_paused = true;
});
show_seq_dl = true;
if (!all_are_seq_dl && there_are_seq_dl)
show_seq_dl = false;
show_f_l_piece_prio = true;
if (!all_are_f_l_piece_prio && there_are_f_l_piece_prio)
show_f_l_piece_prio = false;
if (all_are_downloaded) {
this.hideItem('SequentialDownload');
this.hideItem('FirstLastPiecePrio');
} else {
if (!show_seq_dl && show_f_l_piece_prio)
this.menu.getElement('a[href$=FirstLastPiecePrio]').parentNode.addClass('separator');
else
this.menu.getElement('a[href$=FirstLastPiecePrio]').parentNode.removeClass('separator');
if (show_seq_dl)
this.showItem('SequentialDownload');
else
this.hideItem('SequentialDownload');
if (show_f_l_piece_prio)
this.showItem('FirstLastPiecePrio');
else
this.hideItem('FirstLastPiecePrio');
this.setItemChecked('SequentialDownload', all_are_seq_dl);
this.setItemChecked('FirstLastPiecePrio', all_are_f_l_piece_prio);
}
if (all_are_paused) {
this.showItem('Start');
this.hideItem('Pause');
} else {
if (there_are_paused) {
this.showItem('Start');
this.showItem('Pause');
} else {
this.hideItem('Start');
this.showItem('Pause');
}
}
},
//show menu
show: function(trigger) {
//this.menu.fade('in');
this.updateMenuItems();
this.fx.start(1);
this.fireEvent('show');
this.shown = true;
@ -147,15 +227,21 @@ var ContextMenu = new Class({ @@ -147,15 +227,21 @@ var ContextMenu = new Class({
return this;
},
//disable an item
disableItem: function(item) {
this.menu.getElements('a[href$=' + item + ']').addClass('disabled');
setItemChecked: function(item, checked) {
this.menu.getElement('a[href$=' + item + ']').firstChild.style.opacity =
checked ? '1' : '0';
return this;
},
//hide an item
hideItem: function(item) {
this.menu.getElement('a[href$=' + item + ']').parentNode.addClass('invisible');
return this;
},
//enable an item
enableItem: function(item) {
this.menu.getElements('a[href$=' + item + ']').removeClass('disabled');
//show an item
showItem: function(item) {
this.menu.getElement('a[href$=' + item + ']').parentNode.removeClass('invisible');
return this;
},

18
src/webui/www/public/scripts/dynamicTable.js

@ -42,18 +42,20 @@ var dynamicTable = new Class({ @@ -42,18 +42,20 @@ var dynamicTable = new Class({
this.priority_hidden = false;
this.progressIndex = progressIndex;
this.context_menu = context_menu;
this.table.sortedColumn = 'name'; // Default is NAME
this.table.reverseSort = false;
this.table.sortedColumn = getLocalStorageItem('sorted_column', 'name');
this.table.reverseSort = getLocalStorageItem('reverse_sort', 'false');;
},
setSortedColumn : function (column) {
if (column != this.table.sortedColumn) {
this.table.sortedColumn = column;
this.table.reverseSort = false;
this.table.reverseSort = 'false';
} else {
// Toggle sort order
this.table.reverseSort = !this.table.reverseSort;
this.table.reverseSort = this.table.reverseSort == 'true' ? 'false' : 'true';
}
localStorage.setItem('sorted_column', column);
localStorage.setItem('reverse_sort', this.table.reverseSort);
},
getCurrentTorrentHash : function () {
@ -100,11 +102,13 @@ var dynamicTable = new Class({ @@ -100,11 +102,13 @@ var dynamicTable = new Class({
this.priority_hidden = false;
},
insertRow : function (id, row, data, status, pos) {
insertRow : function (id, row, data, attrs, pos) {
if (this.rows.has(id)) {
return;
}
var tr = new Element('tr');
for (var a in attrs)
tr.set(a, attrs[a]);
tr.addClass("menu-target");
this.rows.set(id, tr);
for (var i = 0; i < row.length; i++) {
@ -244,12 +248,14 @@ var dynamicTable = new Class({ @@ -244,12 +248,14 @@ var dynamicTable = new Class({
}, this);
},
updateRow : function (id, row, data, status, newpos) {
updateRow : function (id, row, data, attrs, newpos) {
if (!this.rows.has(id)) {
return false;
}
var tr = this.rows.get(id);
for (var a in attrs)
tr.set(a, attrs[a]);
var tds = tr.getElements('td');
for (var i = 0; i < row.length; i++) {
if (i == 1)

60
src/webui/www/public/scripts/mocha-init.js

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
/* -----------------------------------------------------------------
ATTACH MOCHA LINK EVENTS
Notes: Here is where you define your windows and the events that open them.
If you are not using links to run Mocha methods you can remove this function.
ATTACH MOCHA LINK EVENTS
Notes: Here is where you define your windows and the events that open them.
If you are not using links to run Mocha methods you can remove this function.
If you need to add link events to links within windows you are creating, do
it in the onContentLoaded function of the new window.
If you need to add link events to links within windows you are creating, do
it in the onContentLoaded function of the new window.
----------------------------------------------------------------- */
/* Define localStorage object for older browsers */
@ -22,6 +22,13 @@ if (typeof localStorage == 'undefined') { @@ -22,6 +22,13 @@ if (typeof localStorage == 'undefined') {
}
}
function getLocalStorageItem(name, defaultVal) {
val = localStorage.getItem(name);
if (val === null || val === undefined)
val = defaultVal;
return val;
}
initializeWindows = function() {
function addClickEvent(el, fn) {
@ -48,6 +55,7 @@ initializeWindows = function() { @@ -48,6 +55,7 @@ initializeWindows = function() {
width: 500,
height: 300
});
updateTransferList();
});
addClickEvent('preferences', function(e) {
@ -87,6 +95,7 @@ initializeWindows = function() { @@ -87,6 +95,7 @@ initializeWindows = function() {
width: 600,
height: 130
});
updateTransferList();
});
globalUploadLimitFN = function() {
@ -125,6 +134,34 @@ initializeWindows = function() { @@ -125,6 +134,34 @@ initializeWindows = function() {
}
};
toggleSequentialDownloadFN = function() {
var h = myTable.selectedIds();
if (h.length) {
new Request({
url: 'command/toggleSequentialDownload',
method: 'post',
data: {
hashes: h.join("|")
}
}).send();
updateTransferList();
}
};
toggleFirstLastPiecePrioFN = function() {
var h = myTable.selectedIds();
if (h.length) {
new Request({
url: 'command/toggleFirstLastPiecePrio',
method: 'post',
data: {
hashes: h.join("|")
}
}).send();
updateTransferList();
}
};
globalDownloadLimitFN = function() {
new MochaUI.Window({
id: 'downloadLimitPage',
@ -164,10 +201,10 @@ initializeWindows = function() { @@ -164,10 +201,10 @@ initializeWindows = function() {
deleteFN = function() {
var h = myTable.selectedIds();
/*if(h.length && confirm('_(Are you sure you want to delete the selected torrents from the transfer list?)')) {
h.each(function(item, index){
new Request({url: 'command/delete', method: 'post', data: {hash: item}}).send();
});
}*/
h.each(function(item, index){
new Request({url: 'command/delete', method: 'post', data: {hash: item}}).send();
});
}*/
if (h.length) {
new MochaUI.Window({
id: 'confirmDeletionPage',
@ -181,6 +218,7 @@ initializeWindows = function() { @@ -181,6 +218,7 @@ initializeWindows = function() {
width: 424,
height: 140
});
updateTransferList();
}
};
@ -201,6 +239,7 @@ initializeWindows = function() { @@ -201,6 +239,7 @@ initializeWindows = function() {
}
}).send();
});
updateTransferList();
}
};
@ -216,6 +255,7 @@ initializeWindows = function() { @@ -216,6 +255,7 @@ initializeWindows = function() {
}
}).send();
});
updateTransferList();
}
};
@ -248,6 +288,7 @@ initializeWindows = function() { @@ -248,6 +288,7 @@ initializeWindows = function() {
}
}).send();
});
updateTransferList();
}
});
@ -276,6 +317,7 @@ initializeWindows = function() { @@ -276,6 +317,7 @@ initializeWindows = function() {
hashes: h.join("|")
}
}).send();
updateTransferList();
}
}

10
src/webui/www/public/transferlist.html

@ -52,11 +52,17 @@ @@ -52,11 +52,17 @@
ForceRecheck : function (element, ref) {
recheckFN();
},
UploadLimit : function (element, red) {
UploadLimit : function (element, ref) {
uploadLimitFN();
},
DownloadLimit : function (element, red) {
DownloadLimit : function (element, ref) {
downloadLimitFN();
},
SequentialDownload : function (element, ref) {
toggleSequentialDownloadFN();
},
FirstLastPiecePrio : function (element, ref) {
toggleFirstLastPiecePrioFN();
}
},
offsets : {

Loading…
Cancel
Save