1 | /*************************************************************************** |
2 | * Copyright (C) 2005-2014 by the Quassel Project * |
3 | * devel@quassel-irc.org * |
4 | * * |
5 | * This program is free software; you can redistribute it and/or modify * |
6 | * it under the terms of the GNU General Public License as published by * |
7 | * the Free Software Foundation; either version 2 of the License, or * |
8 | * (at your option) version 3. * |
9 | * * |
10 | * This program is distributed in the hope that it will be useful, * |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
13 | * GNU General Public License for more details. * |
14 | * * |
15 | * You should have received a copy of the GNU General Public License * |
16 | * along with this program; if not, write to the * |
17 | * Free Software Foundation, Inc., * |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
19 | ***************************************************************************/ |
20 | |
21 | #include "aliasesmodel.h" |
22 | |
23 | #include <QDebug> |
24 | #include <QStringList> |
25 | |
26 | #include "client.h" |
27 | #include "signalproxy.h" |
28 | |
29 | AliasesModel::AliasesModel(QObject *parent) |
30 | : QAbstractItemModel(parent), |
31 | _configChanged(false), |
32 | _modelReady(false) |
33 | { |
34 | // we need this signal for future connects to reset the data; |
35 | connect(Client::instance(), SIGNAL(connected()), this, SLOT(clientConnected())); |
36 | connect(Client::instance(), SIGNAL(disconnected()), this, SLOT(clientDisconnected())); |
37 | |
38 | if (Client::isConnected()) |
39 | clientConnected(); |
40 | else |
41 | emit modelReady(false); |
42 | } |
43 | |
44 | |
45 | QVariant AliasesModel::data(const QModelIndex &index, int role) const |
46 | { |
47 | if (!_modelReady) |
48 | return QVariant(); |
49 | |
50 | if (!index.isValid() || index.row() >= rowCount() || index.column() >= columnCount()) |
51 | return QVariant(); |
52 | |
53 | switch (role) { |
54 | case Qt::ToolTipRole: |
55 | switch (index.column()) { |
56 | case 0: |
57 | return tr("<b>The shortcut for the alias</b><br />" |
58 | "It can be used as a regular slash command.<br /><br />" |
59 | "<b>Example:</b> \"foo\" can be used per /foo" ); |
60 | case 1: |
61 | return tr("<b>The string the shortcut will be expanded to</b><br />" |
62 | "<b>special variables:</b><br />" |
63 | " - <b>$i</b> represents the i'th parameter.<br />" |
64 | " - <b>$i..j</b> represents the i'th to j'th parameter separated by spaces.<br />" |
65 | " - <b>$i..</b> represents all parameters from i on separated by spaces.<br />" |
66 | " - <b>$i:hostname</b> represents the hostname of the user identified by the i'th parameter or a * if unknown.<br />" |
67 | " - <b>$0</b> the whole string.<br />" |
68 | " - <b>$nick</b> your current nickname<br />" |
69 | " - <b>$channel</b> the name of the selected channel<br /><br />" |
70 | "Multiple commands can be separated with semicolons<br /><br />" |
71 | "<b>Example:</b> \"Test $1; Test $2; Test All $0\" will be expanded to three separate messages \"Test 1\", \"Test 2\" and \"Test All 1 2 3\" when called like /test 1 2 3" ); |
72 | default: |
73 | return QVariant(); |
74 | } |
75 | case Qt::DisplayRole: |
76 | case Qt::EditRole: |
77 | switch (index.column()) { |
78 | case 0: |
79 | return aliasManager()[index.row()].name; |
80 | case 1: |
81 | return aliasManager()[index.row()].expansion; |
82 | default: |
83 | return QVariant(); |
84 | } |
85 | default: |
86 | return QVariant(); |
87 | } |
88 | } |
89 | |
90 | |
91 | bool AliasesModel::setData(const QModelIndex &index, const QVariant &value, int role) |
92 | { |
93 | if (!_modelReady) |
94 | return false; |
95 | |
96 | if (!index.isValid() || index.row() >= rowCount() || index.column() >= columnCount() || role != Qt::EditRole) |
97 | return false; |
98 | |
99 | QString newValue = value.toString(); |
100 | if (newValue.isEmpty()) |
101 | return false; |
102 | |
103 | switch (index.column()) { |
104 | case 0: |
105 | if (aliasManager().contains(newValue)) { |
106 | return false; |
107 | } |
108 | else { |
109 | cloneAliasManager()[index.row()].name = newValue; |
110 | return true; |
111 | } |
112 | case 1: |
113 | cloneAliasManager()[index.row()].expansion = newValue; |
114 | return true; |
115 | default: |
116 | return false; |
117 | } |
118 | } |
119 | |
120 | |
121 | void AliasesModel::newAlias() |
122 | { |
123 | QString newName("alias" ); |
124 | int i = 0; |
125 | AliasManager &manager = cloneAliasManager(); |
126 | while (manager.contains(newName)) { |
127 | i++; |
128 | newName = QString("alias%1" ).arg(i); |
129 | } |
130 | beginInsertRows(QModelIndex(), rowCount(), rowCount()); |
131 | manager.addAlias(newName, "Expansion" ); |
132 | endInsertRows(); |
133 | } |
134 | |
135 | |
136 | void AliasesModel::loadDefaults() |
137 | { |
138 | if (!_modelReady) |
139 | return; |
140 | |
141 | AliasManager &manager = cloneAliasManager(); |
142 | |
143 | if (!manager.isEmpty()) { |
144 | beginRemoveRows(QModelIndex(), 0, rowCount() - 1); |
145 | for (int i = rowCount() - 1; i >= 0; i--) |
146 | manager.removeAt(i); |
147 | endRemoveRows(); |
148 | } |
149 | |
150 | AliasManager::AliasList defaults = AliasManager::defaults(); |
151 | beginInsertRows(QModelIndex(), 0, defaults.count() - 1); |
152 | foreach(AliasManager::Alias alias, defaults) { |
153 | manager.addAlias(alias.name, alias.expansion); |
154 | } |
155 | endInsertRows(); |
156 | } |
157 | |
158 | |
159 | void AliasesModel::removeAlias(int index) |
160 | { |
161 | if (index < 0 || index >= rowCount()) |
162 | return; |
163 | |
164 | AliasManager &manager = cloneAliasManager(); |
165 | beginRemoveRows(QModelIndex(), index, index); |
166 | manager.removeAt(index); |
167 | endRemoveRows(); |
168 | } |
169 | |
170 | |
171 | Qt::ItemFlags AliasesModel::flags(const QModelIndex &index) const |
172 | { |
173 | if (!index.isValid()) { |
174 | return Qt::ItemIsDropEnabled; |
175 | } |
176 | else { |
177 | return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable; |
178 | } |
179 | } |
180 | |
181 | |
182 | QVariant AliasesModel::(int section, Qt::Orientation orientation, int role) const |
183 | { |
184 | QStringList ; |
185 | header << tr("Alias" ) |
186 | << tr("Expansion" ); |
187 | |
188 | if (orientation == Qt::Horizontal && role == Qt::DisplayRole) |
189 | return header[section]; |
190 | |
191 | return QVariant(); |
192 | } |
193 | |
194 | |
195 | QModelIndex AliasesModel::index(int row, int column, const QModelIndex &parent) const |
196 | { |
197 | Q_UNUSED(parent); |
198 | if (row >= rowCount() || column >= columnCount()) |
199 | return QModelIndex(); |
200 | |
201 | return createIndex(row, column); |
202 | } |
203 | |
204 | |
205 | const AliasManager &AliasesModel::aliasManager() const |
206 | { |
207 | if (_configChanged) |
208 | return _clonedAliasManager; |
209 | else |
210 | return *Client::aliasManager(); |
211 | } |
212 | |
213 | |
214 | AliasManager &AliasesModel::aliasManager() |
215 | { |
216 | if (_configChanged) |
217 | return _clonedAliasManager; |
218 | else |
219 | return *Client::aliasManager(); |
220 | } |
221 | |
222 | |
223 | AliasManager &AliasesModel::cloneAliasManager() |
224 | { |
225 | if (!_configChanged) { |
226 | _clonedAliasManager = *Client::aliasManager(); |
227 | _configChanged = true; |
228 | emit configChanged(true); |
229 | } |
230 | return _clonedAliasManager; |
231 | } |
232 | |
233 | |
234 | void AliasesModel::revert() |
235 | { |
236 | if (!_configChanged) |
237 | return; |
238 | |
239 | _configChanged = false; |
240 | emit configChanged(false); |
241 | beginResetModel(); |
242 | endResetModel(); |
243 | } |
244 | |
245 | |
246 | void AliasesModel::commit() |
247 | { |
248 | if (!_configChanged) |
249 | return; |
250 | |
251 | Client::aliasManager()->requestUpdate(_clonedAliasManager.toVariantMap()); |
252 | revert(); |
253 | } |
254 | |
255 | |
256 | void AliasesModel::initDone() |
257 | { |
258 | _modelReady = true; |
259 | beginResetModel(); |
260 | endResetModel(); |
261 | emit modelReady(true); |
262 | } |
263 | |
264 | |
265 | void AliasesModel::clientConnected() |
266 | { |
267 | connect(Client::aliasManager(), SIGNAL(updated()), SLOT(revert())); |
268 | if (Client::aliasManager()->isInitialized()) |
269 | initDone(); |
270 | else |
271 | connect(Client::aliasManager(), SIGNAL(initDone()), SLOT(initDone())); |
272 | } |
273 | |
274 | |
275 | void AliasesModel::clientDisconnected() |
276 | { |
277 | // clear |
278 | _clonedAliasManager = ClientAliasManager(); |
279 | _modelReady = false; |
280 | beginResetModel(); |
281 | endResetModel(); |
282 | emit modelReady(false); |
283 | } |
284 | |