1 /*
2 SPDX-FileCopyrightText: 2007 Joris Guisson <joris.guisson@gmail.com>
3 SPDX-FileCopyrightText: 2007 Ivan Vasic <ivasic@gmail.com>
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "queuemanagerwidget.h"
8
9 #include <QAction>
10 #include <QBoxLayout>
11 #include <QHeaderView>
12 #include <QLineEdit>
13 #include <QToolBar>
14 #include <QTreeView>
15
16 #include <KConfigGroup>
17 #include <KLocalizedString>
18 #include <KStandardGuiItem>
19
20 #include "queuemanagermodel.h"
21 #include <torrent/queuemanager.h>
22 #include <util/log.h>
23
24 using namespace bt;
25
26 namespace kt
27 {
QueueManagerWidget(QueueManager * qman,QWidget * parent)28 QueueManagerWidget::QueueManagerWidget(QueueManager *qman, QWidget *parent)
29 : QWidget(parent)
30 , qman(qman)
31 {
32 QHBoxLayout *layout = new QHBoxLayout(this);
33 layout->setMargin(0);
34 layout->setSpacing(0);
35 QVBoxLayout *vbox = new QVBoxLayout();
36 vbox->setMargin(0);
37 vbox->setSpacing(0);
38 view = new QTreeView(this);
39 view->setUniformRowHeights(true);
40 toolbar = new QToolBar(this);
41 toolbar->setOrientation(Qt::Vertical);
42 toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
43 layout->addWidget(toolbar);
44
45 search = new QLineEdit(this);
46 search->setPlaceholderText(i18n("Search"));
47 search->setClearButtonEnabled(true);
48 search->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
49 connect(search, &QLineEdit::textChanged, this, &QueueManagerWidget::searchTextChanged);
50 search->hide();
51 vbox->addWidget(search);
52 vbox->addWidget(view);
53 layout->addLayout(vbox);
54
55 show_search = toolbar->addAction(QIcon::fromTheme(QStringLiteral("edit-find")), i18n("Show Search"));
56 show_search->setToolTip(i18n("Show or hide the search bar"));
57 show_search->setCheckable(true);
58 connect(show_search, &QAction::toggled, this, &QueueManagerWidget::showSearch);
59
60 move_top = toolbar->addAction(QIcon::fromTheme(QStringLiteral("go-top")), i18n("Move Top"), this, &QueueManagerWidget::moveTopClicked);
61 move_top->setToolTip(i18n("Move a torrent to the top of the queue"));
62
63 move_up = toolbar->addAction(QIcon::fromTheme(QStringLiteral("go-up")), i18n("Move Up"), this, &QueueManagerWidget::moveUpClicked);
64 move_up->setToolTip(i18n("Move a torrent up in the queue"));
65
66 move_down = toolbar->addAction(QIcon::fromTheme(QStringLiteral("go-down")), i18n("Move Down"), this, &QueueManagerWidget::moveDownClicked);
67 move_down->setToolTip(i18n("Move a torrent down in the queue"));
68
69 move_bottom = toolbar->addAction(QIcon::fromTheme(QStringLiteral("go-bottom")), i18n("Move Bottom"), this, &QueueManagerWidget::moveBottomClicked);
70 move_bottom->setToolTip(i18n("Move a torrent to the bottom of the queue"));
71
72 show_downloads = toolbar->addAction(QIcon::fromTheme(QStringLiteral("arrow-down")), i18n("Show Downloads"));
73 show_downloads->setToolTip(i18n("Show all downloads"));
74 show_downloads->setCheckable(true);
75 connect(show_downloads, &QAction::toggled, this, &QueueManagerWidget::showDownloads);
76
77 show_uploads = toolbar->addAction(QIcon::fromTheme(QStringLiteral("arrow-up")), i18n("Show Uploads"));
78 show_uploads->setToolTip(i18n("Show all uploads"));
79 show_uploads->setCheckable(true);
80 connect(show_uploads, &QAction::toggled, this, &QueueManagerWidget::showUploads);
81
82 show_not_queued = toolbar->addAction(QIcon::fromTheme(QStringLiteral("kt-queue-manager")), i18n("Show Not Queued"));
83 show_not_queued->setToolTip(i18n("Show all not queued torrents"));
84 show_not_queued->setCheckable(true);
85 connect(show_not_queued, &QAction::toggled, this, &QueueManagerWidget::showNotQueued);
86
87 model = new QueueManagerModel(qman, this);
88 view->setModel(model);
89 view->setRootIsDecorated(false);
90 view->setAlternatingRowColors(true);
91 view->setSelectionBehavior(QAbstractItemView::SelectRows);
92 view->setSortingEnabled(false);
93 view->setDragDropMode(QAbstractItemView::InternalMove);
94 view->setDragEnabled(true);
95 view->setAcceptDrops(true);
96 view->setDropIndicatorShown(true);
97 view->setAutoScroll(true);
98 view->setSelectionMode(QAbstractItemView::ContiguousSelection);
99
100 connect(view->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QueueManagerWidget::selectionChanged);
101
102 updateButtons();
103 }
104
~QueueManagerWidget()105 QueueManagerWidget::~QueueManagerWidget()
106 {
107 }
108
onTorrentAdded(bt::TorrentInterface * tc)109 void QueueManagerWidget::onTorrentAdded(bt::TorrentInterface *tc)
110 {
111 model->onTorrentAdded(tc);
112 }
113
onTorrentRemoved(bt::TorrentInterface * tc)114 void QueueManagerWidget::onTorrentRemoved(bt::TorrentInterface *tc)
115 {
116 model->onTorrentRemoved(tc);
117 }
118
moveUpClicked()119 void QueueManagerWidget::moveUpClicked()
120 {
121 const QModelIndexList sel = view->selectionModel()->selectedRows();
122 QList<int> rows;
123 for (const QModelIndex &idx : sel)
124 rows.append(idx.row());
125
126 if (rows.isEmpty() || rows.front() == 0)
127 return;
128
129 model->moveUp(rows.front(), rows.count());
130
131 QItemSelection nsel;
132 int cols = model->columnCount(QModelIndex());
133 QModelIndex top_left = model->index(rows.front() - 1, 0);
134 QModelIndex bottom_right = model->index(rows.back() - 1, cols - 1);
135 nsel.select(top_left, bottom_right);
136 view->selectionModel()->select(nsel, QItemSelectionModel::Select);
137 if (!indexVisible(top_left))
138 view->scrollTo(top_left, QAbstractItemView::PositionAtCenter);
139
140 updateButtons();
141 }
142
moveDownClicked()143 void QueueManagerWidget::moveDownClicked()
144 {
145 const QModelIndexList sel = view->selectionModel()->selectedRows();
146 QList<int> rows;
147 for (const QModelIndex &idx : sel)
148 rows.append(idx.row());
149
150 int rowcount = model->rowCount(QModelIndex());
151 if (rows.isEmpty() || rows.back() == rowcount - 1)
152 return;
153
154 model->moveDown(rows.front(), rows.count());
155
156 QItemSelection nsel;
157 int cols = model->columnCount(QModelIndex());
158 QModelIndex top_left = model->index(rows.front() + 1, 0);
159 QModelIndex bottom_right = model->index(rows.back() + 1, cols - 1);
160 nsel.select(top_left, bottom_right);
161 view->selectionModel()->select(nsel, QItemSelectionModel::Select);
162 if (!indexVisible(top_left))
163 view->scrollTo(top_left, QAbstractItemView::PositionAtCenter);
164
165 updateButtons();
166 }
167
moveTopClicked()168 void QueueManagerWidget::moveTopClicked()
169 {
170 const QModelIndexList sel = view->selectionModel()->selectedRows();
171 QList<int> rows;
172 for (const QModelIndex &idx : sel)
173 rows.append(idx.row());
174
175 if (rows.isEmpty() || rows.front() == 0)
176 return;
177
178 model->moveTop(rows.front(), rows.count());
179
180 QItemSelection nsel;
181 int cols = model->columnCount(QModelIndex());
182 nsel.select(model->index(0, 0), model->index(rows.count() - 1, cols - 1));
183 view->selectionModel()->select(nsel, QItemSelectionModel::Select);
184 view->scrollToTop();
185
186 updateButtons();
187 }
188
moveBottomClicked()189 void QueueManagerWidget::moveBottomClicked()
190 {
191 const QModelIndexList sel = view->selectionModel()->selectedRows();
192 QList<int> rows;
193 for (const QModelIndex &idx : sel)
194 rows.append(idx.row());
195
196 int rowcount = model->rowCount(QModelIndex());
197 if (rows.isEmpty() || rows.back() == rowcount - 1)
198 return;
199
200 model->moveBottom(rows.front(), rows.count());
201
202 QItemSelection nsel;
203 int cols = model->columnCount(QModelIndex());
204 nsel.select(model->index(rowcount - rows.count(), 0), model->index(rowcount - 1, cols - 1));
205 view->selectionModel()->select(nsel, QItemSelectionModel::Select);
206 view->scrollToBottom();
207
208 updateButtons();
209 }
210
saveState(KSharedConfigPtr cfg)211 void QueueManagerWidget::saveState(KSharedConfigPtr cfg)
212 {
213 KConfigGroup g = cfg->group("QueueManagerWidget");
214 QByteArray s = view->header()->saveState();
215 g.writeEntry("view_state", s.toBase64());
216 g.writeEntry("search_text", search->text());
217 g.writeEntry("search_bar_visible", show_search->isChecked());
218 g.writeEntry("show_uploads", show_uploads->isChecked());
219 g.writeEntry("show_downloads", show_downloads->isChecked());
220 g.writeEntry("show_not_queued", show_not_queued->isChecked());
221 }
222
loadState(KSharedConfigPtr cfg)223 void QueueManagerWidget::loadState(KSharedConfigPtr cfg)
224 {
225 KConfigGroup g = cfg->group("QueueManagerWidget");
226 QByteArray s = QByteArray::fromBase64(g.readEntry("view_state", QByteArray()));
227 if (!s.isEmpty())
228 view->header()->restoreState(s);
229
230 QString st = g.readEntry("search_text", QString());
231 if (!st.isEmpty())
232 search->setText(st);
233
234 show_search->setChecked(g.readEntry("search_bar_visible", false));
235 show_downloads->setChecked(g.readEntry("show_downloads", true));
236 show_uploads->setChecked(g.readEntry("show_uploads", true));
237 show_not_queued->setChecked(g.readEntry("show_not_queued", true));
238 }
239
update()240 void QueueManagerWidget::update()
241 {
242 model->update();
243 }
244
searchTextChanged(const QString & t)245 void QueueManagerWidget::searchTextChanged(const QString &t)
246 {
247 QModelIndex idx = model->find(t);
248 if (idx.isValid()) {
249 view->scrollTo(idx, QAbstractItemView::PositionAtCenter);
250 }
251 }
252
showSearch(bool on)253 void QueueManagerWidget::showSearch(bool on)
254 {
255 search->setVisible(on);
256 }
257
showDownloads(bool on)258 void QueueManagerWidget::showDownloads(bool on)
259 {
260 model->setShowDownloads(on);
261 }
262
showUploads(bool on)263 void QueueManagerWidget::showUploads(bool on)
264 {
265 model->setShowUploads(on);
266 }
267
showNotQueued(bool on)268 void QueueManagerWidget::showNotQueued(bool on)
269 {
270 model->setShowNotQueued(on);
271 }
272
indexVisible(const QModelIndex & idx)273 bool QueueManagerWidget::indexVisible(const QModelIndex &idx)
274 {
275 QRect r = view->visualRect(idx);
276 return view->viewport()->rect().contains(r);
277 }
278
selectionChanged(const QItemSelection & selected,const QItemSelection & deselected)279 void QueueManagerWidget::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
280 {
281 Q_UNUSED(selected);
282 Q_UNUSED(deselected);
283 updateButtons();
284 }
285
updateButtons()286 void QueueManagerWidget::updateButtons()
287 {
288 QModelIndexList idx = view->selectionModel()->selectedRows();
289 if (idx.count() == 0) {
290 move_top->setEnabled(false);
291 move_up->setEnabled(false);
292 move_down->setEnabled(false);
293 move_bottom->setEnabled(false);
294 } else {
295 move_top->setEnabled(idx.front().row() != 0);
296 move_up->setEnabled(idx.front().row() != 0);
297
298 int rows = model->rowCount(QModelIndex());
299 move_down->setEnabled(idx.back().row() != rows - 1);
300 move_bottom->setEnabled(idx.back().row() != rows - 1);
301 }
302 }
303
304 }
305