1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8 * Copyright (C) 2005 by Riku Leino *
9 * tsoots@gmail.com *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
25 ***************************************************************************/
26 #include <QCheckBox>
27 #include <QDebug>
28 #include <QEvent>
29 #include <QPainter>
30 #include <QPushButton>
31 #include <QVBoxLayout>
32
33 #include "iconmanager.h"
34 #include "prefsmanager.h"
35 #include "scraction.h"
36 #include "scribuscore.h"
37 #include "ui/scmwmenumanager.h"
38 #include "undogui.h"
39
40
UndoGui(QWidget * parent,const char * name,Qt::WindowFlags f)41 UndoGui::UndoGui(QWidget* parent, const char* name, Qt::WindowFlags f) : ScDockPalette(parent, name, f)
42 {
43 languageChange();
44 }
45
languageChange()46 void UndoGui::languageChange()
47 {
48 setWindowTitle( tr("Action History"));
49 }
50
51 /*** UndoWidget ***************************************************************/
52
UndoWidget(QWidget * parent,const char * name)53 UndoWidget::UndoWidget(QWidget* parent, const char* name) : UndoGui(parent, name)
54 {
55 auto &actions = ScCore->primaryMainWindow()->scrActions;
56 auto menuManager = ScCore->primaryMainWindow()->scrMenuMgr;
57
58 //Scribus action based toolbar button construction
59 parent->addAction(actions["editUndoAction"]);
60 parent->addAction(actions["editRedoAction"]);
61
62 menuManager->createMenu("undoButtonMenu", "undoButtonMenu");
63 menuManager->createMenu("redoButtonMenu", "redoButtonMenu");
64 undoMenu = menuManager->undoMenu();
65 redoMenu = menuManager->redoMenu();
66
67 parent->addAction(actions["editCut"]);
68 parent->addAction(actions["editCopy"]);
69 parent->addAction(actions["editPaste"]);
70
71 connect(undoMenu, SIGNAL(triggered(QAction*)), this, SLOT(undoMenuClicked(QAction*)));
72 connect(redoMenu, SIGNAL(triggered(QAction*)), this, SLOT(redoMenuClicked(QAction*)));
73 }
74
clear()75 void UndoWidget::clear()
76 {
77 undoMenu->clear();
78 undoItems.clear();
79 //Scribus disable
80 ScCore->primaryMainWindow()->scrActions["editUndoAction"]->setEnabled(false);
81 redoMenu->clear();
82 redoItems.clear();
83 //Scribus disable;
84 ScCore->primaryMainWindow()->scrActions["editRedoAction"]->setEnabled(false);
85 }
86
undoClicked()87 void UndoWidget::undoClicked()
88 {
89 if (!undoItems.empty())
90 emit undo(1);
91 }
92
redoClicked()93 void UndoWidget::redoClicked()
94 {
95 if (!redoItems.empty())
96 emit redo(1);
97 }
98
undoMenuClicked(QAction * id)99 void UndoWidget::undoMenuClicked(QAction *id)
100 {
101 int steps = undoMenu->actions().indexOf(id) + 1;
102 emit undo(steps);
103 }
104
redoMenuClicked(QAction * id)105 void UndoWidget::redoMenuClicked(QAction *id)
106 {
107 int steps = redoMenu->actions().indexOf(id) + 1;
108 emit redo(steps);
109 }
110
insertUndoItem(UndoObject * target,UndoState * state)111 void UndoWidget::insertUndoItem(UndoObject* target, UndoState* state)
112 {
113 undoItems.insert(undoItems.begin(), QString( tr("%1: %2", "undo target: action (f.e. Text frame: Resize)")).arg(target->getUName(), state->getName()));
114 clearRedo();
115 updateUndoMenu();
116 updateRedoMenu();
117 }
118
insertRedoItem(UndoObject * target,UndoState * state)119 void UndoWidget::insertRedoItem(UndoObject* target, UndoState* state)
120 {
121 redoItems.push_back(QString( tr("%1: %2", "undo target: action (f.e. Text frame: Resize)")).arg(target->getUName(), state->getName()));
122 updateRedoMenu();
123 updateUndoMenu();
124 }
125
clearRedo()126 void UndoWidget::clearRedo()
127 {
128 redoItems.erase(redoItems.begin(), redoItems.end());
129 updateRedoMenu();
130 }
131
updateUndoMenu()132 void UndoWidget::updateUndoMenu()
133 {
134 undoMenu->clear();
135 for (uint i = 0; i < MENU_HEIGHT && i < undoItems.size(); ++i)
136 undoMenu->addAction(undoItems[i]);
137 updateUndoActions();
138 }
139
updateRedoMenu()140 void UndoWidget::updateRedoMenu()
141 {
142 redoMenu->clear();
143 for (uint i = 0; i < MENU_HEIGHT && i < redoItems.size(); ++i)
144 redoMenu->addAction(redoItems[i]);
145 updateUndoActions();
146 }
147
updateUndoActions()148 void UndoWidget::updateUndoActions()
149 {
150 ScCore->primaryMainWindow()->scrActions["editUndoAction"]->setEnabled(undoMenu->actions().count() != 0);
151 ScCore->primaryMainWindow()->scrActions["editRedoAction"]->setEnabled(redoMenu->actions().count() != 0);
152 }
153
updateUndo(int steps)154 void UndoWidget::updateUndo(int steps)
155 {
156 for (int i = 0; i < steps; ++i)
157 {
158 redoItems.insert(redoItems.begin(), undoItems[0]);
159 undoItems.erase(undoItems.begin());
160 }
161 updateUndoMenu();
162 updateRedoMenu();
163 }
164
updateRedo(int steps)165 void UndoWidget::updateRedo(int steps)
166 {
167 for (int i = 0; i < steps; ++i)
168 {
169 undoItems.insert(undoItems.begin(), redoItems[0]);
170 redoItems.erase(redoItems.begin());
171 }
172 updateUndoMenu();
173 updateRedoMenu();
174 }
175
popBack()176 void UndoWidget::popBack()
177 {
178 if (!undoItems.empty())
179 {
180 undoItems.erase(undoItems.end() - 1);
181 updateUndoMenu();
182 }
183 }
184
~UndoWidget()185 UndoWidget::~UndoWidget()
186 {
187
188 }
189
190 /*** UndoPalette **************************************************************/
191
UndoPalette(QWidget * parent,const char * name)192 UndoPalette::UndoPalette(QWidget* parent, const char* name) : UndoGui(parent, name)
193 {
194 setObjectName(QString::fromLocal8Bit(name));
195 setMinimumSize( QSize(220, 240) );
196 setSizePolicy( QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
197
198 container = new QWidget(this);
199 currentSelection = 0;
200 redoItems = 0;
201 QVBoxLayout* layout = new QVBoxLayout(container);
202 layout->setContentsMargins(3, 3, 3, 3);
203 layout->setSpacing(3);
204 objectBox = new QCheckBox(this);
205 layout->addWidget(objectBox);
206
207 undoList = new QListWidget(this);
208 undoList->setSelectionMode(QAbstractItemView::SingleSelection);
209 undoList->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
210 layout->addWidget(undoList);
211
212 QHBoxLayout* buttonLayout = new QHBoxLayout;
213 buttonLayout->setContentsMargins(0, 0, 0, 0);
214 buttonLayout->setSpacing(6);
215 undoButton = new QPushButton(IconManager::instance().loadPixmap("16/edit-undo.png"), "", this);
216 buttonLayout->addWidget(undoButton);
217 redoButton = new QPushButton(IconManager::instance().loadPixmap("16/edit-redo.png"), "", this);
218 buttonLayout->addWidget(redoButton);
219 //Save the translated key sequence - hopefully we get the translated one here!
220 initialUndoKS = undoButton->shortcut();
221 initialRedoKS = redoButton->shortcut();
222 layout->addLayout(buttonLayout);
223 setWidget(container);
224
225 updateFromPrefs();
226 languageChange();
227 connect(&PrefsManager::instance(), SIGNAL(prefsChanged()), this, SLOT(updateFromPrefs()));
228 connect(undoButton, SIGNAL(clicked()), this, SLOT(undoClicked()));
229 connect(redoButton, SIGNAL(clicked()), this, SLOT(redoClicked()));
230 connect(undoList, SIGNAL(currentRowChanged(int)), this, SLOT(undoListClicked(int)));
231 connect(undoList, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(showToolTip(QListWidgetItem*)));
232 connect(undoList, SIGNAL(viewportEntered()), this, SLOT(removeToolTip()));
233 connect(objectBox, SIGNAL(toggled(bool)), this, SLOT(objectCheckBoxClicked(bool)));
234 connect(ScCore->primaryMainWindow()->scrActions["editActionMode"], SIGNAL(toggled(bool)),
235 objectBox, SLOT(setChecked(bool)));
236 connect(objectBox, SIGNAL(toggled(bool)),
237 ScCore->primaryMainWindow()->scrActions["editActionMode"], SLOT(setChecked(bool)));
238 }
239
clear()240 void UndoPalette::clear()
241 {
242 disconnect(undoList, SIGNAL(currentRowChanged(int)), this, SLOT(undoListClicked(int)));
243 undoList->clear();
244 undoList->addItem( tr("Initial State"));
245 undoButton->setEnabled(false);
246 redoButton->setEnabled(false);
247 connect(undoList, SIGNAL(currentRowChanged(int)), this, SLOT(undoListClicked(int)));
248 }
249
updateFromPrefs()250 void UndoPalette::updateFromPrefs()
251 {
252 undoButton->setShortcut(ScCore->primaryMainWindow()->scrActions["editUndoAction"]->shortcut());
253 redoButton->setShortcut(ScCore->primaryMainWindow()->scrActions["editRedoAction"]->shortcut());
254 }
255
changeEvent(QEvent * e)256 void UndoPalette::changeEvent(QEvent *e)
257 {
258 if (e->type() == QEvent::LanguageChange)
259 languageChange();
260 else
261 UndoGui::changeEvent(e);
262 }
263
languageChange()264 void UndoPalette::languageChange()
265 {
266 UndoGui::languageChange();
267
268 objectBox->setText( tr("Show Selected Object Only"));
269 undoButton->setText( tr("&Undo"));
270 redoButton->setText( tr("&Redo"));
271
272 objectBox->setToolTip( "<qt>" + tr( "Show the action history for the selected item only. This changes the effect of the undo/redo buttons to act on the object or document." ) + "</qt>" );
273 undoButton->setToolTip( "<qt>" + tr( "Undo the last action for either the current object or the document" ) + "</qt>");
274 redoButton->setToolTip( "<qt>" + tr( "Redo the last action for either the current object or the document" ) + "</qt>");
275 }
276
insertUndoItem(UndoObject * target,UndoState * state)277 void UndoPalette::insertUndoItem(UndoObject* target, UndoState* state)
278 {
279 clearRedo();
280 undoList->addItem(new UndoItem(target->getUName(), state->getName(),
281 state->getDescription(), target->getUPixmap(),
282 state->getPixmap(), true));
283 currentSelection = undoList->count() - 1;
284 updateList();
285 }
286
insertRedoItem(UndoObject * target,UndoState * state)287 void UndoPalette::insertRedoItem(UndoObject* target, UndoState* state)
288 {
289 if (undoList->count() == 1)
290 {
291 undoList->setCurrentItem(undoList->item(0));
292 currentSelection = 0;
293 }
294 undoList->addItem(new UndoItem(target->getUName(), state->getName(),
295 state->getDescription(), target->getUPixmap(),
296 state->getPixmap(), false));
297 updateList();
298 }
299
updateUndo(int steps)300 void UndoPalette::updateUndo(int steps)
301 {
302 if (undoList->row(undoList->currentItem()) == currentSelection)
303 {
304 currentSelection -= steps;
305 updateList();
306 }
307 }
308
updateRedo(int steps)309 void UndoPalette::updateRedo(int steps)
310 {
311 if (undoList->row(undoList->currentItem()) == currentSelection)
312 {
313 currentSelection += steps;
314 updateList();
315 }
316 }
317
popBack()318 void UndoPalette::popBack()
319 {
320 if (undoList->count() > 1)
321 {
322 delete undoList->takeItem(0);
323 currentSelection = undoList->count() - 1;
324 }
325 }
326
updateList()327 void UndoPalette::updateList()
328 {
329 undoList->setCurrentRow(currentSelection);
330 redoButton->setEnabled(currentSelection < undoList->count() - 1);
331 undoButton->setEnabled(currentSelection > 0);
332 undoList->scrollToItem(undoList->item(currentSelection));
333 for (int i = 0; i < undoList->count(); ++i)
334 {
335 UndoItem *item = dynamic_cast<UndoItem*>(undoList->item(i));
336 if (!item)
337 continue;
338
339 item->setUndoAction(currentSelection >= i);
340 }
341 }
342
updateUndoActions()343 void UndoPalette::updateUndoActions()
344 {
345 //ScMW->scrActions["editUndoAction"]->setEnabled(currentSelection > 0);
346 //ScMW->scrActions["editRedoAction"]->setEnabled(currentSelection < undoList->numRows() - 1);
347 }
348
clearRedo()349 void UndoPalette::clearRedo()
350 {
351 for (int i = (undoList->count() - 1); i > currentSelection; --i)
352 delete undoList->takeItem(i);
353 }
354
undoClicked()355 void UndoPalette::undoClicked()
356 {
357 emit undo(1);
358 }
359
redoClicked()360 void UndoPalette::redoClicked()
361 {
362 emit redo(1);
363 }
364
undoListClicked(int i)365 void UndoPalette::undoListClicked(int i)
366 {
367 if (i == currentSelection || (i == 0 && undoList->count() == 1))
368 return;
369 if (i > currentSelection)
370 emit redo(i - currentSelection);
371 else if (i < currentSelection)
372 emit undo(currentSelection - i);
373 currentSelection = i;
374 updateList();
375 }
376
objectCheckBoxClicked(bool on)377 void UndoPalette::objectCheckBoxClicked(bool on)
378 {
379 emit objectMode(on);
380 }
381
showToolTip(QListWidgetItem * i)382 void UndoPalette::showToolTip(QListWidgetItem *i)
383 {
384 UndoItem *item = dynamic_cast<UndoItem*>(i);
385 if (item)
386 {
387 QString tip = item->getDescription();
388 if (!tip.isNull()) /*TODO: Doesn't make sense! */
389 undoList->setToolTip(tip);
390 }
391 else
392 removeToolTip();
393 }
394
removeToolTip()395 void UndoPalette::removeToolTip()
396 {
397 undoList->setToolTip("");
398 }
399
~UndoPalette()400 UndoPalette::~UndoPalette()
401 {
402
403 }
404
405 /*** UndoPalette::UndoItem ****************************************************/
406
UndoItem()407 UndoPalette::UndoItem::UndoItem()
408 {
409 targetpixmap = nullptr;
410 actionpixmap = nullptr;
411 isUndoAction_ = true;
412 }
413
UndoItem(const UndoItem & another)414 UndoPalette::UndoItem::UndoItem(const UndoItem &another)
415 {
416 target = another.target;
417 action = another.action;
418 description = another.description;
419 targetpixmap = another.targetpixmap;
420 actionpixmap = another.actionpixmap;
421 isUndoAction_ = another.isUndoAction_;
422 }
423
UndoItem(const QString & targetName,const QString & actionName,const QString & actionDescription,QPixmap * targetPixmap,QPixmap * actionPixmap,bool isUndoAction,QListWidget * parent)424 UndoPalette::UndoItem::UndoItem(const QString &targetName,
425 const QString &actionName,
426 const QString &actionDescription,
427 QPixmap *targetPixmap,
428 QPixmap *actionPixmap,
429 bool isUndoAction,
430 QListWidget * parent
431 )
432 : QListWidgetItem(parent),
433 targetpixmap(targetPixmap),
434 actionpixmap(actionPixmap),
435 target(targetName),
436 action(actionName),
437 description(actionDescription),
438 isUndoAction_(isUndoAction)
439 {
440 /*TODO: 16x16 is hardcoded, because images automatically scaled by QIcon are no longer recognizable
441 would be better to have the icons designed for 16x16*/
442 if (targetPixmap)
443 {
444 QPixmap pixmap;
445 if (!targetPixmap->isNull())
446 pixmap = targetPixmap->scaled(16, 16);
447 if (actionPixmap && !actionPixmap->isNull())
448 {
449 QPainter p;
450 p.begin(&pixmap);
451 p.drawPixmap(0,0, actionPixmap->scaled(16, 16));
452 p.end();
453 }
454 setIcon(pixmap);
455 }
456 else
457 {
458 if (actionPixmap && !actionPixmap->isNull())
459 setIcon(actionPixmap->scaled(16, 16));
460 }
461 setText(tr("%1 - %2\n%3").arg(targetName, actionName, actionDescription));
462 }
463
getDescription()464 QString UndoPalette::UndoItem::getDescription()
465 {
466 return description;
467 }
468
isUndoAction()469 bool UndoPalette::UndoItem::isUndoAction()
470 {
471 return isUndoAction_;
472 }
473
setUndoAction(bool isUndo)474 void UndoPalette::UndoItem::setUndoAction(bool isUndo)
475 {
476 isUndoAction_ = isUndo;
477 QFont f = font();
478 f.setItalic(!isUndoAction_);
479 setFont(f);
480 }
481
~UndoItem()482 UndoPalette::UndoItem::~UndoItem()
483 {
484
485 }
486