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