Some work about adaptive color scheme for Web UI (PR #19901)
http://[316:c51a:62a3:8b9::4]/d4708/qBittorrent/src/branch/adaptive-webui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
8.1 KiB
222 lines
8.1 KiB
/* |
|
* Bittorrent Client using Qt and libtorrent. |
|
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru> |
|
* |
|
* This program is free software; you can redistribute it and/or |
|
* modify it under the terms of the GNU General Public License |
|
* as published by the Free Software Foundation; either version 2 |
|
* of the License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program; if not, write to the Free Software |
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
* |
|
* In addition, as a special exception, the copyright holders give permission to |
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
|
* modified versions of it that use the same license as the "OpenSSL" library), |
|
* and distribute the linked executables. You must obey the GNU General Public |
|
* License in all respects for all of the code used other than "OpenSSL". If you |
|
* modify file(s), you may extend this exception to your version of the file(s), |
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
|
* exception statement from your version. |
|
*/ |
|
|
|
#include "categoryfilterwidget.h" |
|
|
|
#include <QMenu> |
|
|
|
#include "base/bittorrent/session.h" |
|
#include "base/global.h" |
|
#include "gui/torrentcategorydialog.h" |
|
#include "gui/uithememanager.h" |
|
#include "gui/utils.h" |
|
#include "categoryfiltermodel.h" |
|
#include "categoryfilterproxymodel.h" |
|
|
|
namespace |
|
{ |
|
QString getCategoryFilter(const CategoryFilterProxyModel *const model, const QModelIndex &index) |
|
{ |
|
QString categoryFilter; // Defaults to All |
|
if (index.isValid()) |
|
{ |
|
if (!index.parent().isValid() && (index.row() == 1)) |
|
categoryFilter = u""_s; // Uncategorized |
|
else if (index.parent().isValid() || (index.row() > 1)) |
|
categoryFilter = model->categoryName(index); |
|
} |
|
|
|
return categoryFilter; |
|
} |
|
} |
|
|
|
CategoryFilterWidget::CategoryFilterWidget(QWidget *parent) |
|
: QTreeView(parent) |
|
{ |
|
auto *proxyModel = new CategoryFilterProxyModel(this); |
|
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); |
|
proxyModel->setSourceModel(new CategoryFilterModel(this)); |
|
setModel(proxyModel); |
|
setFrameShape(QFrame::NoFrame); |
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); |
|
setUniformRowHeights(true); |
|
setHeaderHidden(true); |
|
setIconSize(Utils::Gui::smallIconSize()); |
|
#ifdef Q_OS_MACOS |
|
setAttribute(Qt::WA_MacShowFocusRect, false); |
|
#endif |
|
m_defaultIndentation = indentation(); |
|
if (!BitTorrent::Session::instance()->isSubcategoriesEnabled()) |
|
setIndentation(0); |
|
setContextMenuPolicy(Qt::CustomContextMenu); |
|
sortByColumn(0, Qt::AscendingOrder); |
|
setCurrentIndex(model()->index(0, 0)); |
|
|
|
connect(this, &QTreeView::collapsed, this, &CategoryFilterWidget::callUpdateGeometry); |
|
connect(this, &QTreeView::expanded, this, &CategoryFilterWidget::callUpdateGeometry); |
|
connect(this, &QWidget::customContextMenuRequested, this, &CategoryFilterWidget::showMenu); |
|
connect(selectionModel(), &QItemSelectionModel::currentRowChanged |
|
, this, &CategoryFilterWidget::onCurrentRowChanged); |
|
connect(model(), &QAbstractItemModel::modelReset, this, &CategoryFilterWidget::callUpdateGeometry); |
|
} |
|
|
|
QString CategoryFilterWidget::currentCategory() const |
|
{ |
|
QModelIndex current; |
|
const auto selectedRows = selectionModel()->selectedRows(); |
|
if (!selectedRows.isEmpty()) |
|
current = selectedRows.first(); |
|
|
|
return getCategoryFilter(static_cast<CategoryFilterProxyModel *>(model()), current); |
|
} |
|
|
|
void CategoryFilterWidget::onCurrentRowChanged(const QModelIndex ¤t, [[maybe_unused]] const QModelIndex &previous) |
|
{ |
|
emit categoryChanged(getCategoryFilter(static_cast<CategoryFilterProxyModel *>(model()), current)); |
|
} |
|
|
|
void CategoryFilterWidget::showMenu() |
|
{ |
|
QMenu *menu = new QMenu(this); |
|
menu->setAttribute(Qt::WA_DeleteOnClose); |
|
|
|
menu->addAction(UIThemeManager::instance()->getIcon(u"list-add"_s), tr("Add category...") |
|
, this, &CategoryFilterWidget::addCategory); |
|
|
|
const auto selectedRows = selectionModel()->selectedRows(); |
|
if (!selectedRows.empty() && !CategoryFilterModel::isSpecialItem(selectedRows.first())) |
|
{ |
|
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) |
|
{ |
|
menu->addAction(UIThemeManager::instance()->getIcon(u"list-add"_s), tr("Add subcategory...") |
|
, this, &CategoryFilterWidget::addSubcategory); |
|
} |
|
|
|
menu->addAction(UIThemeManager::instance()->getIcon(u"edit-rename"_s, u"document-edit"_s), tr("Edit category...") |
|
, this, &CategoryFilterWidget::editCategory); |
|
menu->addAction(UIThemeManager::instance()->getIcon(u"edit-clear"_s, u"list-remove"_s), tr("Remove category") |
|
, this, &CategoryFilterWidget::removeCategory); |
|
} |
|
|
|
menu->addAction(UIThemeManager::instance()->getIcon(u"edit-clear"_s, u"list-remove"_s), tr("Remove unused categories") |
|
, this, &CategoryFilterWidget::removeUnusedCategories); |
|
menu->addSeparator(); |
|
menu->addAction(UIThemeManager::instance()->getIcon(u"torrent-start"_s, u"media-playback-start"_s), tr("Resume torrents") |
|
, this, &CategoryFilterWidget::actionResumeTorrentsTriggered); |
|
menu->addAction(UIThemeManager::instance()->getIcon(u"torrent-stop"_s, u"media-playback-pause"_s), tr("Pause torrents") |
|
, this, &CategoryFilterWidget::actionPauseTorrentsTriggered); |
|
menu->addAction(UIThemeManager::instance()->getIcon(u"list-remove"_s), tr("Remove torrents") |
|
, this, &CategoryFilterWidget::actionDeleteTorrentsTriggered); |
|
|
|
menu->popup(QCursor::pos()); |
|
} |
|
|
|
void CategoryFilterWidget::callUpdateGeometry() |
|
{ |
|
if (!BitTorrent::Session::instance()->isSubcategoriesEnabled()) |
|
setIndentation(0); |
|
else |
|
setIndentation(m_defaultIndentation); |
|
|
|
updateGeometry(); |
|
} |
|
|
|
QSize CategoryFilterWidget::sizeHint() const |
|
{ |
|
// The sizeHint must depend on viewportSizeHint, |
|
// otherwise widget will not correctly adjust the |
|
// size when subcategories are used. |
|
const QSize viewportSize {viewportSizeHint()}; |
|
return |
|
{ |
|
viewportSize.width(), |
|
viewportSize.height() + static_cast<int>(0.5 * sizeHintForRow(0)) |
|
}; |
|
} |
|
|
|
QSize CategoryFilterWidget::minimumSizeHint() const |
|
{ |
|
QSize size = sizeHint(); |
|
size.setWidth(6); |
|
return size; |
|
} |
|
|
|
void CategoryFilterWidget::rowsInserted(const QModelIndex &parent, int start, int end) |
|
{ |
|
QTreeView::rowsInserted(parent, start, end); |
|
|
|
// Expand all parents if the parent(s) of the node are not expanded. |
|
QModelIndex p = parent; |
|
while (p.isValid()) |
|
{ |
|
if (!isExpanded(p)) |
|
expand(p); |
|
p = model()->parent(p); |
|
} |
|
|
|
updateGeometry(); |
|
} |
|
|
|
void CategoryFilterWidget::addCategory() |
|
{ |
|
TorrentCategoryDialog::createCategory(this); |
|
} |
|
|
|
void CategoryFilterWidget::addSubcategory() |
|
{ |
|
TorrentCategoryDialog::createCategory(this, currentCategory()); |
|
} |
|
|
|
void CategoryFilterWidget::editCategory() |
|
{ |
|
TorrentCategoryDialog::editCategory(this, currentCategory()); |
|
} |
|
|
|
void CategoryFilterWidget::removeCategory() |
|
{ |
|
const auto selectedRows = selectionModel()->selectedRows(); |
|
if (!selectedRows.empty() && !CategoryFilterModel::isSpecialItem(selectedRows.first())) |
|
{ |
|
BitTorrent::Session::instance()->removeCategory( |
|
static_cast<CategoryFilterProxyModel *>(model())->categoryName(selectedRows.first())); |
|
updateGeometry(); |
|
} |
|
} |
|
|
|
void CategoryFilterWidget::removeUnusedCategories() |
|
{ |
|
auto *session = BitTorrent::Session::instance(); |
|
for (const QString &category : asConst(session->categories())) |
|
{ |
|
if (model()->data(static_cast<CategoryFilterProxyModel *>(model())->index(category), Qt::UserRole) == 0) |
|
session->removeCategory(category); |
|
} |
|
updateGeometry(); |
|
}
|
|
|