1 /*
2     SPDX-FileCopyrightText: 2002-2010 Peter Hedlund <peter.hedlund@kdemail.net>
3     SPDX-License-Identifier: GPL-2.0-or-later
4 */
5 
6 #include "kwqcommands.h"
7 
8 #include <QApplication>
9 #include <QClipboard>
10 #include <QHeaderView>
11 
12 #include "kwqtablemodel.h"
13 
copyToClipboard(QTableView * view)14 void copyToClipboard(QTableView * view)
15 {
16   QModelIndexList selIndexes = view->selectionModel()->selectedIndexes();
17   if( selIndexes.isEmpty())
18      return;
19   int tr = selIndexes.first().row();
20   int lc = selIndexes.first().column();
21   int br = selIndexes.last().row();
22   int rc = selIndexes.last().column();
23 
24   QString s;
25   for (int r = tr; r <= br; ++r)
26   {
27     for (int c = lc; c <= rc; ++c)
28     {
29       QVariant v =  view->model()->data(view->model()->index(r, c, QModelIndex()), Qt::DisplayRole);
30       s.append(v.toString());
31       s.append('\t');
32     }
33     s.append('\n');
34   }
35   QApplication::clipboard()->setText(s.trimmed());
36 }
37 
38 
KWQUndoCommand(KWQTableView * view)39 KWQUndoCommand::KWQUndoCommand(KWQTableView * view) : QUndoCommand()
40 {
41   m_view = view;
42   m_currentIndex = m_view->selectionModel()->currentIndex();
43   m_selectedIndexes = m_view->selectionModel()->selectedIndexes();
44   if (m_selectedIndexes.isEmpty())
45       m_selectedIndexes.append(m_currentIndex);
46 
47   foreach (const QModelIndex &index, m_selectedIndexes) {
48     IndexAndData id;
49     id.index = index;
50     id.data = m_view->model()->data(index, Qt::DisplayRole);
51     id.image = m_view->model()->data(index, KWQTableModel::ImageRole);
52     id.sound = m_view->model()->data(index, KWQTableModel::SoundRole);
53     id.height = m_view->rowHeight(index.row());
54     m_indexAndData.append(id);
55   }
56 }
57 
58 
undo()59 void KWQUndoCommand::undo()
60 {
61   m_view->selectionModel()->clear();
62   foreach (const IndexAndData &id, m_indexAndData) {
63     m_view->model()->setData(id.index, id.data, Qt::EditRole);
64     m_view->model()->setData(id.index, id.image, KWQTableModel::ImageRole);
65     m_view->model()->setData(id.index, id.sound, KWQTableModel::SoundRole);
66     m_view->selectionModel()->select(id.index, QItemSelectionModel::Select);
67   }
68   m_view->selectionModel()->setCurrentIndex(m_currentIndex, QItemSelectionModel::Current);
69 }
70 
71 
KWQCommandClear(KWQTableView * view)72 KWQCommandClear::KWQCommandClear(KWQTableView * view) : KWQUndoCommand(view)
73 {
74   setText(i18nc("@item:inmenu undo clear", "Clear"));
75 }
76 
77 
redo()78 void KWQCommandClear::redo()
79 {
80   view()->selectionModel()->clear();
81   foreach (const QModelIndex &index, oldSelectedIndexes()) {
82     if (Prefs::clearText() || Prefs::clearAll())
83       view()->model()->setData(index, QVariant(), Qt::EditRole);
84     if (Prefs::clearImageLink() || Prefs::clearAll())
85       view()->model()->setData(index, QVariant(), KWQTableModel::ImageRole);
86     if (Prefs::clearSoundLink() || Prefs::clearAll())
87       view()->model()->setData(index, QVariant(), KWQTableModel::SoundRole);
88     view()->selectionModel()->select(index, QItemSelectionModel::Select);
89   }
90   view()->selectionModel()->setCurrentIndex(oldCurrentIndex(), QItemSelectionModel::Current);
91 }
92 
93 
KWQCommandCut(KWQTableView * view)94 KWQCommandCut::KWQCommandCut(KWQTableView * view) : KWQCommandClear(view)
95 {
96   setText(i18nc("@item:inmenu undo cut", "Cut"));
97 }
98 
99 
redo()100 void KWQCommandCut::redo()
101 {
102   copyToClipboard(view());
103   KWQCommandClear::redo();
104 }
105 
106 
KWQCommandPaste(KWQTableView * view)107 KWQCommandPaste::KWQCommandPaste(KWQTableView * view) : KWQUndoCommand(view)
108 {
109   setText(i18nc("@item:inmenu undo paste", "Paste"));
110   m_rowCount = view->model()->rowCount();
111 }
112 
undo()113 void KWQCommandPaste::undo()
114 {
115   foreach (const IndexAndData &id, m_pasteIndexAndData)
116     view()->model()->setData(id.index, id.data, Qt::EditRole);
117 
118   while (view()->model()->rowCount(QModelIndex()) > m_rowCount) {
119       view()->model()->removeRows(view()->model()->rowCount() - 1, 1, QModelIndex());
120     }
121 
122   KWQUndoCommand::undo();
123 }
124 
redo()125 void KWQCommandPaste::redo()
126 {
127   QModelIndexList selIndexes = oldSelectedIndexes();
128   if(selIndexes.isEmpty())
129      return;
130   QModelIndex topLeft = view()->model()->index(selIndexes.first().row(), selIndexes.first().column(), QModelIndex());
131   QModelIndex bottomRight = view()->model()->index(selIndexes.last().row(), selIndexes.last().column(), QModelIndex());
132 
133   int tr;
134   int lc;
135   int ar = tr = topLeft.row();
136   int ac = lc = topLeft.column();
137   int rc = bottomRight.column();
138   int br = bottomRight.row();
139 
140   QString s = QApplication::clipboard()->text();
141   QStringList sl;
142 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
143   sl = s.split('\n', QString::SkipEmptyParts);
144 #else
145   sl = s.split('\n', Qt::SkipEmptyParts);
146 #endif
147   if (sl.isEmpty())
148     return;
149   QStringList sr;
150   int i = 0;
151 
152   if (selIndexes.count() == 1) //one cell selected
153   {
154     //Do we need to add entries (rows)?
155     while (sl.count() + tr > view()->model()->rowCount(QModelIndex())) {
156       view()->model()->insertRows(view()->model()->rowCount(), 1, QModelIndex());
157     }
158 
159     br = tr + sl.count() - 1;
160 
161     if (lc == 0) //left col?
162       if (sl[0].indexOf('\t') > -1)
163         rc = 1; //expand to second column;
164 
165     while (i < sl.count() && br <= view()->model()->rowCount(QModelIndex())) {
166       ac = lc;
167 
168       sr = sl.at(i).split('\t');
169       int c = 0;
170       while (ac <= rc) {
171         IndexAndData id;
172         id.index = view()->model()->index(ar, ac);
173         id.data = view()->model()->data(id.index, Qt::DisplayRole);
174         m_pasteIndexAndData.append(id);
175         if (c < sr.count())
176             view()->model()->setData(id.index, QVariant(sr[c]), Qt::EditRole);
177         view()->selectionModel()->select(id.index, QItemSelectionModel::Select);
178         ac++;
179         c++;
180       }
181       ar++;
182       i++;
183     }
184   }
185   else
186   {
187     while (i < sl.count() && ar <= br) {
188       ac = lc;
189 
190       sr = sl.at(i).split('\t');
191       int c = 0;
192       while (ac <= rc) {
193         if (view()->selectionModel()->isSelected(view()->model()->index(ar, ac)))
194             if (c < sr.count())
195                 view()->model()->setData(view()->model()->index(ar, ac), QVariant(sr[c]), Qt::EditRole);
196         ac++;
197         c++;
198       }
199       ar++;
200       i++;
201     }
202   }
203 }
204 
205 
KWQCommandSort(QTableView * view,int column)206 KWQCommandSort::KWQCommandSort(QTableView * view, int column)
207 {
208   m_view = view;
209   m_column = column;
210   setText(i18nc("@item:inmenu undo sort", "Sort"));
211 }
212 
213 
undo()214 void KWQCommandSort::undo()
215 {
216   m_view->setUpdatesEnabled(false);
217   static_cast<KWQSortFilterModel*>(m_view->model())->restoreNativeOrder();
218   m_view->horizontalHeader()->setSortIndicatorShown(false);
219   m_view->setUpdatesEnabled(true);
220 }
221 
222 
redo()223 void KWQCommandSort::redo()
224 {
225   int currentRow = m_view->currentIndex().row();
226   int currentColumn = m_view->currentIndex().column();
227   m_view->sortByColumn(m_column, Qt::AscendingOrder);
228   m_view->horizontalHeader()->setSortIndicatorShown(true);
229   m_view->horizontalHeader()->setSortIndicator(m_column, m_view->horizontalHeader()->sortIndicatorOrder());
230   m_view->setCurrentIndex(m_view->model()->index(currentRow, currentColumn, QModelIndex()));
231 }
232 
233 
KWQCommandShuffle(QTableView * view,int column)234 KWQCommandShuffle::KWQCommandShuffle(QTableView * view, int column) : KWQCommandSort(view, column)
235 {
236   m_view = view;
237   setText(i18nc("@item:inmenu undo shuffle", "Shuffle"));
238 }
239 
undo()240 void KWQCommandShuffle::undo()
241 {
242   KWQCommandSort::undo();
243 }
244 
redo()245 void KWQCommandShuffle::redo()
246 {
247   int currentRow = m_view->currentIndex().row();
248   int currentColumn = m_view->currentIndex().column();
249   static_cast<KWQSortFilterModel*>(m_view->model())->shuffle();
250   m_view->horizontalHeader()->setSortIndicatorShown(false);
251   m_view->setCurrentIndex(m_view->model()->index(currentRow, currentColumn, QModelIndex()));
252 }
253 
254 
KWQCommandInsert(KWQTableView * view)255 KWQCommandInsert::KWQCommandInsert(KWQTableView * view) : KWQUndoCommand(view)
256 {
257   setText(i18nc("@item:inmenu undo insert", "Insert"));
258 }
259 
undo()260 void KWQCommandInsert::undo()
261 {
262   QModelIndexList selIndexes = oldSelectedIndexes();
263   QModelIndex topLeft = view()->model()->index(selIndexes.first().row(), selIndexes.first().column(), QModelIndex());
264   QModelIndex bottomRight = view()->model()->index(selIndexes.last().row(), selIndexes.last().column(), QModelIndex());
265 
266   view()->model()->removeRows(topLeft.row(), bottomRight.row() - topLeft.row() + 1, QModelIndex());
267 
268   view()->selectionModel()->clear();
269   view()->setCurrentIndex(view()->model()->index(oldCurrentIndex().row(), oldCurrentIndex().column(), QModelIndex()));
270   view()->selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select);
271 }
272 
redo()273 void KWQCommandInsert::redo()
274 {
275   QModelIndexList selIndexes = oldSelectedIndexes();
276   QModelIndex topLeft = view()->model()->index(selIndexes.first().row(), selIndexes.first().column(), QModelIndex());
277   QModelIndex bottomRight = view()->model()->index(selIndexes.last().row(), selIndexes.last().column(), QModelIndex());
278 
279   view()->model()->insertRows(topLeft.row(), bottomRight.row() - topLeft.row() + 1, QModelIndex());
280 
281   view()->selectionModel()->clear();
282   view()->setCurrentIndex(view()->model()->index(oldCurrentIndex().row(), oldCurrentIndex().column(), QModelIndex()));
283   view()->selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select);
284 }
285 
286 
KWQCommandDelete(KWQTableView * view)287 KWQCommandDelete::KWQCommandDelete(KWQTableView * view) : KWQUndoCommand(view)
288 {
289   setText(i18nc("@item:inmenu undo delete", "Delete"));
290 }
291 
292 
undo()293 void KWQCommandDelete::undo()
294 {
295   QModelIndexList selIndexes = oldSelectedIndexes();
296   QModelIndex topLeft = view()->model()->index(selIndexes.first().row(), selIndexes.first().column(), QModelIndex());
297   QModelIndex bottomRight = view()->model()->index(selIndexes.last().row(), selIndexes.last().column(), QModelIndex());
298 
299   view()->model()->insertRows(topLeft.row(), bottomRight.row() - topLeft.row() + 1, QModelIndex());
300 
301   foreach (const IndexAndData &id, m_deleteIndexAndData)
302     view()->model()->setData(id.index, id.data, Qt::EditRole);
303 
304   view()->selectionModel()->clear();
305   view()->setCurrentIndex(view()->model()->index(oldCurrentIndex().row(), oldCurrentIndex().column(), QModelIndex()));
306   view()->selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select);
307 }
308 
309 
redo()310 void KWQCommandDelete::redo()
311 {
312   QModelIndexList selIndexes = oldSelectedIndexes();
313   QModelIndex topLeft = view()->model()->index(selIndexes.first().row(), selIndexes.first().column(), QModelIndex());
314   QModelIndex bottomRight = view()->model()->index(selIndexes.last().row(), selIndexes.last().column(), QModelIndex());
315 
316   QModelIndex topLeftDeletion = view()->model()->index(selIndexes.first().row(), 0, QModelIndex());
317   QModelIndex bottomRightDeletion = view()->model()->index(selIndexes.last().row(), 1, QModelIndex());
318 
319   QItemSelection deletion(topLeftDeletion, bottomRightDeletion);
320   m_deleteIndexAndData.clear();
321   foreach (const QModelIndex &idx, deletion.indexes()) {
322     IndexAndData id;
323     id.index = idx;
324     id.data = view()->model()->data(id.index, Qt::DisplayRole);
325     m_deleteIndexAndData.append(id);
326   }
327 
328   view()->model()->removeRows(topLeft.row(), bottomRight.row() - topLeft.row() + 1, QModelIndex());
329 
330   view()->selectionModel()->clear();
331   view()->setCurrentIndex(view()->model()->index(oldCurrentIndex().row(), oldCurrentIndex().column(), QModelIndex()));
332   view()->selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select);
333 }
334 
335 
KWQCommandUnmarkBlank(KWQTableView * view)336 KWQCommandUnmarkBlank::KWQCommandUnmarkBlank(KWQTableView * view) : KWQUndoCommand(view)
337 {
338   setText(i18nc("@item:inmenu undo unmark blank", "Unmark Blank"));
339 }
340 
341 
redo()342 void KWQCommandUnmarkBlank::redo()
343 {
344   QString s;
345   view()->selectionModel()->clear();
346   foreach (const QModelIndex &index, oldSelectedIndexes())
347   {
348     s = view()->model()->data(index, Qt::DisplayRole).toString();
349     s = s.remove(delim_start);
350     s = s.remove(delim_end);
351     view()->model()->setData(index, QVariant(s), Qt::EditRole);
352     view()->selectionModel()->select(index, QItemSelectionModel::Select);
353   }
354   view()->selectionModel()->setCurrentIndex(oldCurrentIndex(), QItemSelectionModel::Current);
355 }
356 
357 
KWQCommandIdentifiers(KWQTableView * view,const ColumnDataList & newColumnData)358 KWQCommandIdentifiers::KWQCommandIdentifiers(KWQTableView * view, const ColumnDataList &newColumnData) : KWQUndoCommand(view)
359 {
360   setText(i18nc("@item:inmenu undo column titles", "Column Settings"));
361   m_oldColumnData.clear();
362   ColumnData columnData;
363   columnData.identifier = view->model()->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString();
364   columnData.layout = view->model()->headerData(0, Qt::Horizontal, KWQTableModel::KeyboardLayoutRole).toString();
365   columnData.width = view->model()->headerData(0, Qt::Horizontal, Qt::SizeHintRole).toSize().width();
366   m_oldColumnData.append(columnData);
367 
368   columnData.identifier = view->model()->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString();
369   columnData.layout = view->model()->headerData(1, Qt::Horizontal, KWQTableModel::KeyboardLayoutRole).toString();
370   columnData.width = view->model()->headerData(1, Qt::Horizontal, Qt::SizeHintRole).toSize().width();
371   m_oldColumnData.append(columnData);
372 
373   m_newColumnData = newColumnData;
374 }
375 
376 
undo()377 void KWQCommandIdentifiers::undo()
378 {
379   view()->model()->setHeaderData(0, Qt::Horizontal, m_oldColumnData[0].identifier, Qt::EditRole);
380   view()->model()->setHeaderData(1, Qt::Horizontal, m_oldColumnData[1].identifier, Qt::EditRole);
381 
382   view()->model()->setHeaderData(0, Qt::Horizontal, m_oldColumnData[0].layout, KWQTableModel::KeyboardLayoutRole);
383   view()->model()->setHeaderData(1, Qt::Horizontal, m_oldColumnData[1].layout, KWQTableModel::KeyboardLayoutRole);
384 
385   view()->model()->setHeaderData(0, Qt::Horizontal, QSize(m_oldColumnData[0].width, 25), Qt::SizeHintRole);
386   view()->model()->setHeaderData(1, Qt::Horizontal, QSize(m_oldColumnData[1].width, 25), Qt::SizeHintRole);
387 }
388 
389 
redo()390 void KWQCommandIdentifiers::redo()
391 {
392   view()->model()->setHeaderData(0, Qt::Horizontal, m_newColumnData[0].identifier, Qt::EditRole);
393   view()->model()->setHeaderData(1, Qt::Horizontal, m_newColumnData[1].identifier, Qt::EditRole);
394 
395   view()->model()->setHeaderData(0, Qt::Horizontal, m_newColumnData[0].layout, KWQTableModel::KeyboardLayoutRole);
396   view()->model()->setHeaderData(1, Qt::Horizontal, m_newColumnData[1].layout, KWQTableModel::KeyboardLayoutRole);
397 
398   view()->model()->setHeaderData(0, Qt::Horizontal, QSize(m_newColumnData[0].width, 25), Qt::SizeHintRole);
399   view()->model()->setHeaderData(1, Qt::Horizontal, QSize(m_newColumnData[1].width, 25), Qt::SizeHintRole);
400 }
401 
402 
KWQCommandImage(KWQTableView * view,const QUrl & newUrl)403 KWQCommandImage::KWQCommandImage(KWQTableView *view, const QUrl &newUrl) : KWQUndoCommand(view), m_newUrl(newUrl)
404 {
405   setText(i18nc("@item:inmenu undo link image", "Link Image"));
406   m_oldUrl = QUrl(view->model()->data(oldCurrentIndex(), KWQTableModel::ImageRole).toString());
407 }
408 
409 
undo()410 void KWQCommandImage::undo()
411 {
412   view()->model()->setData(oldCurrentIndex(), QVariant(m_oldUrl), KWQTableModel::ImageRole);
413 }
414 
415 
redo()416 void KWQCommandImage::redo()
417 {
418   view()->model()->setData(oldCurrentIndex(), QVariant(m_newUrl), KWQTableModel::ImageRole);
419 }
420 
421 
KWQCommandSound(KWQTableView * view,const QUrl & newUrl)422 KWQCommandSound::KWQCommandSound(KWQTableView *view, const QUrl &newUrl) : KWQUndoCommand(view), m_newUrl(newUrl)
423 {
424   setText(i18nc("@item:inmenu undo link sound", "Link Sound"));
425   m_oldUrl = QUrl(view->model()->data(oldCurrentIndex(), KWQTableModel::SoundRole).toString());
426 }
427 
428 
undo()429 void KWQCommandSound::undo()
430 {
431   view()->model()->setData(oldCurrentIndex(), QVariant(m_oldUrl), KWQTableModel::SoundRole);
432 }
433 
434 
redo()435 void KWQCommandSound::redo()
436 {
437   view()->model()->setData(oldCurrentIndex(), QVariant(m_newUrl), KWQTableModel::SoundRole);
438 }
439