diff --git a/src/webui/prefjson.cpp b/src/webui/prefjson.cpp index c82fa782d..bf206df39 100644 --- a/src/webui/prefjson.cpp +++ b/src/webui/prefjson.cpp @@ -396,4 +396,3 @@ void prefjson::setPreferences(const QString& json) // Save preferences pref->apply(); } - diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp index 16916b6eb..3000c3464 100644 --- a/src/webui/webapplication.cpp +++ b/src/webui/webapplication.cpp @@ -39,6 +39,7 @@ #include "core/preferences.h" #include "btjson.h" #include "prefjson.h" +#include "jsonutils.h" #include "core/bittorrent/session.h" #include "core/bittorrent/trackerentry.h" #include "core/bittorrent/torrentinfo.h" @@ -677,8 +678,9 @@ void WebApplication::action_command_setLabel() if( m.contains("value") ) { QString label = m["value"].toString(); if (!hash.isEmpty()) { - QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); - QBtSession::instance()->setLabel(h, label); + BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); + if (torrent) + torrent->setLabel(label); } } } diff --git a/src/webui/webui.qrc b/src/webui/webui.qrc index c77d04bdc..407b6b05f 100644 --- a/src/webui/webui.qrc +++ b/src/webui/webui.qrc @@ -27,6 +27,7 @@ www/public/download.html www/public/downloadlimit.html www/public/filters.html + www/public/newlabel.html www/public/preferences.html www/public/preferences_content.html www/public/properties.html diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index f7db8ab31..a0ee74397 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -105,6 +105,11 @@
  • QBT_TR(Pause)QBT_TR QBT_TR(Pause)QBT_TR
  • QBT_TR(Force Resume)QBT_TR QBT_TR(Force Resume)QBT_TR
  • QBT_TR(Delete)QBT_TR QBT_TR(Delete)QBT_TR
  • +
  • + QBT_TR(Label >)QBT_TR + +
  • QBT_TR(Priority)QBT_TR +
    + QBT_TR(Labels)QBT_TR + diff --git a/src/webui/www/public/newlabel.html b/src/webui/www/public/newlabel.html new file mode 100644 index 000000000..2b6ff512e --- /dev/null +++ b/src/webui/www/public/newlabel.html @@ -0,0 +1,64 @@ + + + + + QBT_TR(New Label)QBT_TR + + + + + + +
    +

    QBT_TR(Label)QBT_TR: + +

    + + +
    + + diff --git a/src/webui/www/public/scripts/client.js b/src/webui/www/public/scripts/client.js index b6b0a93ac..72610e33d 100644 --- a/src/webui/www/public/scripts/client.js +++ b/src/webui/www/public/scripts/client.js @@ -30,24 +30,29 @@ var alternativeSpeedLimits = false; var queueing_enabled = true; var syncMainDataTimerPeriod = 1500; -selected_filter = getLocalStorageItem('selected_filter', 'all'); -selected_label = null; +var LABELS_ALL = 1; +var LABELS_UNLABELLED = 2; + +var label_list = {}; + +var selected_label = LABELS_ALL; +var setLabelFilter = function(){}; + +var selected_filter = getLocalStorageItem('selected_filter', 'all'); +var setFilter = function(){}; var loadSelectedLabel = function () { - if (getLocalStorageItem('any_label', '1') == '0') - selected_label = getLocalStorageItem('selected_label', ''); - else - selected_label = null; -} + selected_label = getLocalStorageItem('selected_label', LABELS_ALL); +}; loadSelectedLabel(); -var saveSelectedLabel = function () { - if (selected_label == null) - localStorage.setItem('any_label', '1'); - else { - localStorage.setItem('any_label', '0'); - localStorage.setItem('selected_label', selected_label); +function genHash(string) { + var hash = 0; + for (var i = 0; i < string.length; i++) { + var c = string.charCodeAt(i); + hash = (c + hash * 31) | 0; } + return hash; } window.addEvent('load', function () { @@ -90,6 +95,14 @@ window.addEvent('load', function () { resizeLimit : [100, 300] }); + setLabelFilter = function( hash ) { + selected_label = hash; + localStorage.setItem('selected_label', selected_label); + updateLabelList(); + if (typeof myTable.table != 'undefined') + updateMainData(); + }; + setFilter = function (f) { // Visually Select the right filter $("all_filter").removeClass("selectedFilter"); @@ -148,6 +161,97 @@ window.addEvent('load', function () { var syncMainDataLastResponseId = 0; var serverState = {}; + var removeTorrentFromLabelList = function( hash ) + { + if( hash == null || hash == "" ) return false; + + var removed = false; + Object.each( label_list, function( label ) { + if( Object.contains( label.torrents, hash ) ) { + removed = true; + label.torrents.splice( label.torrents.indexOf( hash ), 1 ); + } + }); + return removed; + }; + + var addTorrentToLabelList = function( torrent ) { + var label = torrent['label']; + if( label == null || label.length === 0 ) { + removeTorrentFromLabelList( torrent['hash'] ); + return false; + } + + var labelHash = genHash( label ); + if( label_list[labelHash] == null ) { + console.log( "addTorrentToLabelList: warning, label not found. label=", label, " label_list=", label_list ); + label_list[labelHash] = { name: label, torrents: [] }; + } + if( !Object.contains(label_list[labelHash].torrents, torrent['hash'] ) ) { + removeTorrentFromLabelList( torrent['hash'] ); + label_list[labelHash].torrents = label_list[labelHash].torrents.combine( [ torrent['hash'] ] ); + return true; + } + return false; + }; + + var updateContextMenu = function () { + var labelList = $('contextLabelList'); + labelList.empty(); + labelList.appendChild(new Element('li', {html: 'QBT_TR(New...)QBT_TR'})); + labelList.appendChild(new Element('li', {html: 'QBT_TR(Reset)QBT_TR'})); + + var first = true; + Object.each(label_list, function (label) { + var labelHash = genHash( label.name ); + var el = new Element('li', {html: '' + label.name + ''}); + if (first) { + el.removeClass(); + el.addClass('separator'); + first = false; + } + labelList.appendChild(el); + }); + }; + + var updateLabelList = function() { + var labelList = $( 'filterLabelList' ); + if( !labelList ) { + return; + } + labelList.empty(); + + var create_link = function( hash, text, count ) + { + var html = '' + + '' + + text + '(' + count + ')' + ''; + + return new Element( 'li', { id: hash, html: html } ); + }; + + var allLabels = 0; + Object.each( label_list, function( label ) { + allLabels += label.torrents.length; + }); + + var unlabelled = myTable.getRowIds().length - allLabels; + labelList.appendChild( create_link( LABELS_ALL, 'QBT_TR(All Labels)QBT_TR', allLabels ) ); + labelList.appendChild( create_link( LABELS_UNLABELLED, 'QBT_TR(Unlabeled)QBT_TR', unlabelled ) ); + + Object.each( label_list, function( label ) { + var labelHash = genHash( label.name ); + labelList.appendChild( create_link( labelHash, label.name, label.torrents.length ) ); + } ); + + var childrens = labelList.childNodes; + for (var i in childrens) { + if( childrens[i].id == selected_label ) { + childrens[i].className = "selectedFilter"; + } + } + }; + var syncMainDataTimer; var syncMainData = function () { var url = new URI('sync/maindata'); @@ -165,15 +269,26 @@ window.addEvent('load', function () { $('error_div').set('html', ''); if (response) { var full_update = (response['full_update'] == true); - if (full_update) + if (full_update) { myTable.rows.erase(); - if (response['rid']) + label_list = {}; + Object.each( response['labels'], function( label ) { + var labelHash = genHash( label ); + label_list[ labelHash ] = { name: label, torrents: [] }; + } ); + } + if (response['rid']) { syncMainDataLastResponseId = response['rid']; - if (response['torrents']) + } + if (response['torrents']) { for (var key in response['torrents']) { response['torrents'][key]['hash'] = key; - myTable.updateRowData(response['torrents'][key]); + myTable.updateRowData( response['torrents'][key] ); + addTorrentToLabelList( response['torrents'][key] ); } + updateLabelList(); + updateContextMenu(); + } if (response['torrents_removed']) response['torrents_removed'].each(function (hash) { myTable.removeRow(hash); diff --git a/src/webui/www/public/scripts/dynamicTable.js b/src/webui/www/public/scripts/dynamicTable.js index ac1062801..c49de75c7 100644 --- a/src/webui/www/public/scripts/dynamicTable.js +++ b/src/webui/www/public/scripts/dynamicTable.js @@ -60,6 +60,7 @@ var dynamicTable = new Class({ this.newColumn('upspeed', 'width: 100px; cursor: pointer', 'QBT_TR(Up Speed)QBT_TR'); this.newColumn('eta', 'width: 100px; cursor: pointer', 'QBT_TR(ETA)QBT_TR'); this.newColumn('ratio', 'width: 100px; cursor: pointer', 'QBT_TR(Ratio)QBT_TR'); + this.newColumn('label', 'width: 100px; cursor: pointer', 'QBT_TR(Label)QBT_TR'); this.columns['state_icon'].onclick = ''; this.columns['state_icon'].dataProperties[0] = 'state'; @@ -279,10 +280,13 @@ var dynamicTable = new Class({ break; } - if (labelName == null) + if (labelName == LABELS_ALL && row['full_data'].label.length > 0) return true; - if (labelName != row['full_data'].label) + if (labelName == LABELS_UNLABELLED && row['full_data'].label.length === 0) + return true; + + if (labelName != genHash( row['full_data'].label) ) return false; return true; diff --git a/src/webui/www/public/scripts/mocha-init.js b/src/webui/www/public/scripts/mocha-init.js index 1fdd5e924..9ff9c36f5 100644 --- a/src/webui/www/public/scripts/mocha-init.js +++ b/src/webui/www/public/scripts/mocha-init.js @@ -309,6 +309,60 @@ initializeWindows = function() { } }; + newLabelFN = function () { + var h = myTable.selectedIds(); + if (h.length) { + new MochaUI.Window({ + id: 'newLabelPage', + title: "QBT_TR(Torrent Label)QBT_TR", + loadMethod: 'iframe', + contentURL: 'newlabel.html?hashes=' + h.join(','), + scrollbars: false, + resizable: false, + maximizable: false, + paddingVertical: 0, + paddingHorizontal: 0, + width: 424, + height: 150 + }); + } + }; + + resetLabelFN = function () { + var h = myTable.selectedIds(); + var label_json = JSON.stringify({value: ''}); + if (h.length) { + h.each(function (hash, index) { + new Request({ + url: 'command/setLabel', + method: 'post', + data: { + hash: hash, + label_obj: label_json + } + }).send(); + }); + } + }; + + updateLabelFN = function (label_hash) { + var label = label_list[label_hash].name; + var label_json = JSON.stringify({value: label}); + var h = myTable.selectedIds(); + if (h.length) { + h.each(function (hash, index) { + new Request({ + url: 'command/setLabel', + method: 'post', + data: { + hash: hash, + label_obj: label_json + } + }).send(); + }); + } + }; + ['pauseAll', 'resumeAll'].each(function(item) { addClickEvent(item, function(e) { new Event(e).stop();