1 /*
2     SPDX-FileCopyrightText: 2009 Joris Guisson <joris.guisson@gmail.com>
3     SPDX-License-Identifier: GPL-2.0-or-later
4 */
5 
6 #include <KLocalizedString>
7 #include <QComboBox>
8 
9 #include "shutdowntorrentmodel.h"
10 #include <interfaces/coreinterface.h>
11 #include <torrent/queuemanager.h>
12 
13 namespace kt
14 {
ShutdownTorrentModel(CoreInterface * core,QObject * parent)15 ShutdownTorrentModel::ShutdownTorrentModel(CoreInterface *core, QObject *parent)
16     : QAbstractTableModel(parent)
17     , qman(core->getQueueManager())
18 {
19     for (kt::QueueManager::iterator i = qman->begin(); i != qman->end(); i++) {
20         TriggerItem cond;
21         cond.checked = false;
22         cond.tc = *i;
23         cond.trigger = DOWNLOADING_COMPLETED;
24         conds.append(cond);
25     }
26 
27     connect(core, &CoreInterface::torrentAdded, this, &ShutdownTorrentModel::torrentAdded);
28     connect(core, &CoreInterface::torrentRemoved, this, &ShutdownTorrentModel::torrentRemoved);
29 }
30 
~ShutdownTorrentModel()31 ShutdownTorrentModel::~ShutdownTorrentModel()
32 {
33 }
34 
torrentAdded(bt::TorrentInterface * tc)35 void ShutdownTorrentModel::torrentAdded(bt::TorrentInterface *tc)
36 {
37     TriggerItem cond;
38     cond.checked = false;
39     cond.tc = tc;
40     cond.trigger = DOWNLOADING_COMPLETED;
41     conds.append(cond);
42     insertRow(conds.count() - 1);
43 }
44 
torrentRemoved(bt::TorrentInterface * tc)45 void ShutdownTorrentModel::torrentRemoved(bt::TorrentInterface *tc)
46 {
47     int idx = 0;
48     for (const TriggerItem &c : qAsConst(conds)) {
49         if (c.tc == tc) {
50             removeRow(idx);
51             break;
52         }
53         idx++;
54     }
55 }
56 
data(const QModelIndex & index,int role) const57 QVariant ShutdownTorrentModel::data(const QModelIndex &index, int role) const
58 {
59     if (!index.isValid() || index.row() < 0 || index.row() >= conds.count())
60         return QVariant();
61 
62     if (role == Qt::CheckStateRole) {
63         if (index.column() != 0)
64             return QVariant();
65 
66         return conds.at(index.row()).checked ? Qt::Checked : Qt::Unchecked;
67     } else if (role == Qt::DisplayRole) {
68         const TriggerItem &cond = conds.at(index.row());
69         switch (index.column()) {
70         case 0:
71             return cond.tc->getDisplayName();
72         case 1:
73             if (cond.trigger == DOWNLOADING_COMPLETED)
74                 return i18n("Downloading finishes");
75             else
76                 return i18n("Seeding finishes");
77         default:
78             return QVariant();
79         }
80     } else if (role == Qt::EditRole) {
81         if (index.column() == 1)
82             return conds.at(index.row()).trigger;
83     }
84 
85     return QVariant();
86 }
87 
columnCount(const QModelIndex & parent) const88 int ShutdownTorrentModel::columnCount(const QModelIndex &parent) const
89 {
90     return parent.isValid() ? 0 : 2;
91 }
92 
rowCount(const QModelIndex & parent) const93 int ShutdownTorrentModel::rowCount(const QModelIndex &parent) const
94 {
95     return parent.isValid() ? 0 : qman->count();
96 }
97 
setData(const QModelIndex & index,const QVariant & value,int role)98 bool ShutdownTorrentModel::setData(const QModelIndex &index, const QVariant &value, int role)
99 {
100     if (!index.isValid() || index.row() < 0 || index.row() >= conds.count())
101         return false;
102 
103     if (role == Qt::CheckStateRole) {
104         TriggerItem &cond = conds[index.row()];
105         Qt::CheckState checked = static_cast<Qt::CheckState>(value.toInt());
106         cond.checked = checked == Qt::Checked;
107         Q_EMIT dataChanged(index, index);
108         return true;
109     } else if (role == Qt::EditRole) {
110         int v = value.toInt();
111         if (v < 0 || v > 1)
112             return false;
113 
114         Trigger trigger = (Trigger)v;
115         TriggerItem &cond = conds[index.row()];
116         cond.trigger = trigger;
117         Q_EMIT dataChanged(index, index);
118         return true;
119     }
120     return false;
121 }
122 
headerData(int section,Qt::Orientation orientation,int role) const123 QVariant ShutdownTorrentModel::headerData(int section, Qt::Orientation orientation, int role) const
124 {
125     if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
126         return QVariant();
127 
128     switch (section) {
129     case 0:
130         return i18n("Torrent");
131     case 1:
132         return i18n("Event");
133     default:
134         return QVariant();
135     }
136 }
137 
insertRows(int row,int count,const QModelIndex & parent)138 bool ShutdownTorrentModel::insertRows(int row, int count, const QModelIndex &parent)
139 {
140     Q_UNUSED(parent);
141     beginInsertRows(QModelIndex(), row, row + count - 1);
142     endInsertRows();
143     return true;
144 }
145 
removeRows(int row,int count,const QModelIndex & parent)146 bool ShutdownTorrentModel::removeRows(int row, int count, const QModelIndex &parent)
147 {
148     Q_UNUSED(parent);
149     beginRemoveRows(QModelIndex(), row, row + count - 1);
150     for (int i = 0; i < count; i++) {
151         conds.takeAt(row);
152     }
153     endRemoveRows();
154     return true;
155 }
156 
flags(const QModelIndex & index) const157 Qt::ItemFlags ShutdownTorrentModel::flags(const QModelIndex &index) const
158 {
159     if (!index.isValid() || index.row() < 0 || index.row() >= conds.count())
160         return {};
161 
162     Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
163     if (index.column() == 0)
164         flags |= Qt::ItemIsUserCheckable;
165 
166     if (index.column() == 1)
167         flags |= Qt::ItemIsEditable;
168 
169     return flags;
170 }
171 
applyRules(Action action,kt::ShutdownRuleSet * rules)172 void ShutdownTorrentModel::applyRules(Action action, kt::ShutdownRuleSet *rules)
173 {
174     rules->clear();
175     for (const TriggerItem &c : qAsConst(conds)) {
176         if (c.checked)
177             rules->addRule(action, SPECIFIC_TORRENT, c.trigger, c.tc);
178     }
179 }
180 
addRule(const kt::ShutdownRule & rule)181 void ShutdownTorrentModel::addRule(const kt::ShutdownRule &rule)
182 {
183     QList<TriggerItem>::iterator i = conds.begin();
184     while (i != conds.end()) {
185         TriggerItem &c = *i;
186         if (c.tc == rule.tc) {
187             c.checked = true;
188             c.trigger = rule.trigger;
189             break;
190         }
191         i++;
192     }
193 }
194 
195 //////////////////////////////////////////////////////
196 
ShutdownTorrentDelegate(QObject * parent)197 ShutdownTorrentDelegate::ShutdownTorrentDelegate(QObject *parent)
198     : QStyledItemDelegate(parent)
199 {
200 }
201 
~ShutdownTorrentDelegate()202 ShutdownTorrentDelegate::~ShutdownTorrentDelegate()
203 {
204 }
205 
createEditor(QWidget * parent,const QStyleOptionViewItem & option,const QModelIndex & index) const206 QWidget *ShutdownTorrentDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
207 {
208     Q_UNUSED(option);
209     Q_UNUSED(index);
210     QComboBox *cb = new QComboBox(parent);
211     cb->addItem(i18n("Downloading finishes"));
212     cb->addItem(i18n("Seeding finishes"));
213     return cb;
214 }
215 
setEditorData(QWidget * editor,const QModelIndex & index) const216 void ShutdownTorrentDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
217 {
218     int value = index.model()->data(index, Qt::EditRole).toInt();
219     QComboBox *cb = static_cast<QComboBox *>(editor);
220     cb->setCurrentIndex(value);
221 }
222 
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index) const223 void ShutdownTorrentDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
224 {
225     QComboBox *cb = static_cast<QComboBox *>(editor);
226     int value = cb->currentIndex();
227     model->setData(index, value, Qt::EditRole);
228 }
229 
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const230 QSize ShutdownTorrentDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
231 {
232     Q_UNUSED(option);
233     Q_UNUSED(index);
234     QComboBox tmp;
235     return tmp.sizeHint();
236 }
237 
updateEditorGeometry(QWidget * editor,const QStyleOptionViewItem & option,const QModelIndex & index) const238 void ShutdownTorrentDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
239 {
240     Q_UNUSED(index);
241     QRect r = option.rect;
242     if (option.rect.height() < editor->sizeHint().height())
243         r.setHeight(editor->sizeHint().height());
244     editor->setGeometry(r);
245 }
246 
247 }
248