|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtGui module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qundogroup.h" |
|
43 #include "qundostack.h" |
|
44 #include "qundostack_p.h" |
|
45 |
|
46 #ifndef QT_NO_UNDOGROUP |
|
47 |
|
48 QT_BEGIN_NAMESPACE |
|
49 |
|
50 class QUndoGroupPrivate : public QObjectPrivate |
|
51 { |
|
52 Q_DECLARE_PUBLIC(QUndoGroup) |
|
53 public: |
|
54 QUndoGroupPrivate() : active(0) {} |
|
55 |
|
56 QUndoStack *active; |
|
57 QList<QUndoStack*> stack_list; |
|
58 }; |
|
59 |
|
60 /*! |
|
61 \class QUndoGroup |
|
62 \brief The QUndoGroup class is a group of QUndoStack objects. |
|
63 \since 4.2 |
|
64 |
|
65 For an overview of the Qt's undo framework, see the |
|
66 \link qundo.html overview\endlink. |
|
67 |
|
68 An application often has multiple undo stacks, one for each opened document. At the |
|
69 same time, an application usually has one undo action and one redo action, which |
|
70 triggers undo or redo in the active document. |
|
71 |
|
72 QUndoGroup is a group of QUndoStack objects, one of which may be active. It has |
|
73 an undo() and redo() slot, which calls QUndoStack::undo() and QUndoStack::redo() |
|
74 for the active stack. It also has the functions createUndoAction() and createRedoAction(). |
|
75 The actions returned by these functions behave in the same way as those returned by |
|
76 QUndoStack::createUndoAction() and QUndoStack::createRedoAction() of the active |
|
77 stack. |
|
78 |
|
79 Stacks are added to a group with addStack() and removed with removeStack(). A stack |
|
80 is implicitly added to a group when it is created with the group as its parent |
|
81 QObject. |
|
82 |
|
83 It is the programmer's responsibility to specify which stack is active by |
|
84 calling QUndoStack::setActive(), usually when the associated document window receives focus. |
|
85 The active stack may also be set with setActiveStack(), and is returned by activeStack(). |
|
86 |
|
87 When a stack is added to a group using addStack(), the group does not take ownership |
|
88 of the stack. This means the stack has to be deleted separately from the group. When |
|
89 a stack is deleted, it is automatically removed from a group. A stack may belong to |
|
90 only one group. Adding it to another group will cause it to be removed from the previous |
|
91 group. |
|
92 |
|
93 A QUndoGroup is also useful in conjunction with QUndoView. If a QUndoView is |
|
94 set to watch a group using QUndoView::setGroup(), it will update itself to display |
|
95 the active stack. |
|
96 */ |
|
97 |
|
98 /*! |
|
99 Creates an empty QUndoGroup object with parent \a parent. |
|
100 |
|
101 \sa addStack() |
|
102 */ |
|
103 |
|
104 QUndoGroup::QUndoGroup(QObject *parent) |
|
105 : QObject(*new QUndoGroupPrivate(), parent) |
|
106 { |
|
107 } |
|
108 |
|
109 /*! |
|
110 Destroys the QUndoGroup. |
|
111 */ |
|
112 QUndoGroup::~QUndoGroup() |
|
113 { |
|
114 // Ensure all QUndoStacks no longer refer to this group. |
|
115 Q_D(QUndoGroup); |
|
116 QList<QUndoStack *>::iterator it = d->stack_list.begin(); |
|
117 QList<QUndoStack *>::iterator end = d->stack_list.end(); |
|
118 while (it != end) { |
|
119 (*it)->d_func()->group = 0; |
|
120 ++it; |
|
121 } |
|
122 } |
|
123 |
|
124 /*! |
|
125 Adds \a stack to this group. The group does not take ownership of the stack. Another |
|
126 way of adding a stack to a group is by specifying the group as the stack's parent |
|
127 QObject in QUndoStack::QUndoStack(). In this case, the stack is deleted when the |
|
128 group is deleted, in the usual manner of QObjects. |
|
129 |
|
130 \sa removeStack() stacks() QUndoStack::QUndoStack() |
|
131 */ |
|
132 |
|
133 void QUndoGroup::addStack(QUndoStack *stack) |
|
134 { |
|
135 Q_D(QUndoGroup); |
|
136 |
|
137 if (d->stack_list.contains(stack)) |
|
138 return; |
|
139 d->stack_list.append(stack); |
|
140 |
|
141 if (QUndoGroup *other = stack->d_func()->group) |
|
142 other->removeStack(stack); |
|
143 stack->d_func()->group = this; |
|
144 } |
|
145 |
|
146 /*! |
|
147 Removes \a stack from this group. If the stack was the active stack in the group, |
|
148 the active stack becomes 0. |
|
149 |
|
150 \sa addStack() stacks() QUndoStack::~QUndoStack() |
|
151 */ |
|
152 |
|
153 void QUndoGroup::removeStack(QUndoStack *stack) |
|
154 { |
|
155 Q_D(QUndoGroup); |
|
156 |
|
157 if (d->stack_list.removeAll(stack) == 0) |
|
158 return; |
|
159 if (stack == d->active) |
|
160 setActiveStack(0); |
|
161 stack->d_func()->group = 0; |
|
162 } |
|
163 |
|
164 /*! |
|
165 Returns a list of stacks in this group. |
|
166 |
|
167 \sa addStack() removeStack() |
|
168 */ |
|
169 |
|
170 QList<QUndoStack*> QUndoGroup::stacks() const |
|
171 { |
|
172 Q_D(const QUndoGroup); |
|
173 return d->stack_list; |
|
174 } |
|
175 |
|
176 /*! |
|
177 Sets the active stack of this group to \a stack. |
|
178 |
|
179 If the stack is not a member of this group, this function does nothing. |
|
180 |
|
181 Synonymous with calling QUndoStack::setActive() on \a stack. |
|
182 |
|
183 The actions returned by createUndoAction() and createRedoAction() will now behave |
|
184 in the same way as those returned by \a stack's QUndoStack::createUndoAction() |
|
185 and QUndoStack::createRedoAction(). |
|
186 |
|
187 \sa QUndoStack::setActive() activeStack() |
|
188 */ |
|
189 |
|
190 void QUndoGroup::setActiveStack(QUndoStack *stack) |
|
191 { |
|
192 Q_D(QUndoGroup); |
|
193 if (d->active == stack) |
|
194 return; |
|
195 |
|
196 if (d->active != 0) { |
|
197 disconnect(d->active, SIGNAL(canUndoChanged(bool)), |
|
198 this, SIGNAL(canUndoChanged(bool))); |
|
199 disconnect(d->active, SIGNAL(undoTextChanged(QString)), |
|
200 this, SIGNAL(undoTextChanged(QString))); |
|
201 disconnect(d->active, SIGNAL(canRedoChanged(bool)), |
|
202 this, SIGNAL(canRedoChanged(bool))); |
|
203 disconnect(d->active, SIGNAL(redoTextChanged(QString)), |
|
204 this, SIGNAL(redoTextChanged(QString))); |
|
205 disconnect(d->active, SIGNAL(indexChanged(int)), |
|
206 this, SIGNAL(indexChanged(int))); |
|
207 disconnect(d->active, SIGNAL(cleanChanged(bool)), |
|
208 this, SIGNAL(cleanChanged(bool))); |
|
209 } |
|
210 |
|
211 d->active = stack; |
|
212 |
|
213 if (d->active == 0) { |
|
214 emit canUndoChanged(false); |
|
215 emit undoTextChanged(QString()); |
|
216 emit canRedoChanged(false); |
|
217 emit redoTextChanged(QString()); |
|
218 emit cleanChanged(true); |
|
219 emit indexChanged(0); |
|
220 } else { |
|
221 connect(d->active, SIGNAL(canUndoChanged(bool)), |
|
222 this, SIGNAL(canUndoChanged(bool))); |
|
223 connect(d->active, SIGNAL(undoTextChanged(QString)), |
|
224 this, SIGNAL(undoTextChanged(QString))); |
|
225 connect(d->active, SIGNAL(canRedoChanged(bool)), |
|
226 this, SIGNAL(canRedoChanged(bool))); |
|
227 connect(d->active, SIGNAL(redoTextChanged(QString)), |
|
228 this, SIGNAL(redoTextChanged(QString))); |
|
229 connect(d->active, SIGNAL(indexChanged(int)), |
|
230 this, SIGNAL(indexChanged(int))); |
|
231 connect(d->active, SIGNAL(cleanChanged(bool)), |
|
232 this, SIGNAL(cleanChanged(bool))); |
|
233 emit canUndoChanged(d->active->canUndo()); |
|
234 emit undoTextChanged(d->active->undoText()); |
|
235 emit canRedoChanged(d->active->canRedo()); |
|
236 emit redoTextChanged(d->active->redoText()); |
|
237 emit cleanChanged(d->active->isClean()); |
|
238 emit indexChanged(d->active->index()); |
|
239 } |
|
240 |
|
241 emit activeStackChanged(d->active); |
|
242 } |
|
243 |
|
244 /*! |
|
245 Returns the active stack of this group. |
|
246 |
|
247 If none of the stacks are active, or if the group is empty, this function |
|
248 returns 0. |
|
249 |
|
250 \sa setActiveStack() QUndoStack::setActive() |
|
251 */ |
|
252 |
|
253 QUndoStack *QUndoGroup::activeStack() const |
|
254 { |
|
255 Q_D(const QUndoGroup); |
|
256 return d->active; |
|
257 } |
|
258 |
|
259 /*! |
|
260 Calls QUndoStack::undo() on the active stack. |
|
261 |
|
262 If none of the stacks are active, or if the group is empty, this function |
|
263 does nothing. |
|
264 |
|
265 \sa redo() canUndo() setActiveStack() |
|
266 */ |
|
267 |
|
268 void QUndoGroup::undo() |
|
269 { |
|
270 Q_D(QUndoGroup); |
|
271 if (d->active != 0) |
|
272 d->active->undo(); |
|
273 } |
|
274 |
|
275 /*! |
|
276 Calls QUndoStack::redo() on the active stack. |
|
277 |
|
278 If none of the stacks are active, or if the group is empty, this function |
|
279 does nothing. |
|
280 |
|
281 \sa undo() canRedo() setActiveStack() |
|
282 */ |
|
283 |
|
284 |
|
285 void QUndoGroup::redo() |
|
286 { |
|
287 Q_D(QUndoGroup); |
|
288 if (d->active != 0) |
|
289 d->active->redo(); |
|
290 } |
|
291 |
|
292 /*! |
|
293 Returns the value of the active stack's QUndoStack::canUndo(). |
|
294 |
|
295 If none of the stacks are active, or if the group is empty, this function |
|
296 returns false. |
|
297 |
|
298 \sa canRedo() setActiveStack() |
|
299 */ |
|
300 |
|
301 bool QUndoGroup::canUndo() const |
|
302 { |
|
303 Q_D(const QUndoGroup); |
|
304 return d->active != 0 && d->active->canUndo(); |
|
305 } |
|
306 |
|
307 /*! |
|
308 Returns the value of the active stack's QUndoStack::canRedo(). |
|
309 |
|
310 If none of the stacks are active, or if the group is empty, this function |
|
311 returns false. |
|
312 |
|
313 \sa canUndo() setActiveStack() |
|
314 */ |
|
315 |
|
316 bool QUndoGroup::canRedo() const |
|
317 { |
|
318 Q_D(const QUndoGroup); |
|
319 return d->active != 0 && d->active->canRedo(); |
|
320 } |
|
321 |
|
322 /*! |
|
323 Returns the value of the active stack's QUndoStack::undoText(). |
|
324 |
|
325 If none of the stacks are active, or if the group is empty, this function |
|
326 returns an empty string. |
|
327 |
|
328 \sa redoText() setActiveStack() |
|
329 */ |
|
330 |
|
331 QString QUndoGroup::undoText() const |
|
332 { |
|
333 Q_D(const QUndoGroup); |
|
334 return d->active == 0 ? QString() : d->active->undoText(); |
|
335 } |
|
336 |
|
337 /*! |
|
338 Returns the value of the active stack's QUndoStack::redoText(). |
|
339 |
|
340 If none of the stacks are active, or if the group is empty, this function |
|
341 returns an empty string. |
|
342 |
|
343 \sa undoText() setActiveStack() |
|
344 */ |
|
345 |
|
346 QString QUndoGroup::redoText() const |
|
347 { |
|
348 Q_D(const QUndoGroup); |
|
349 return d->active == 0 ? QString() : d->active->redoText(); |
|
350 } |
|
351 |
|
352 /*! |
|
353 Returns the value of the active stack's QUndoStack::isClean(). |
|
354 |
|
355 If none of the stacks are active, or if the group is empty, this function |
|
356 returns true. |
|
357 |
|
358 \sa setActiveStack() |
|
359 */ |
|
360 |
|
361 bool QUndoGroup::isClean() const |
|
362 { |
|
363 Q_D(const QUndoGroup); |
|
364 return d->active == 0 || d->active->isClean(); |
|
365 } |
|
366 |
|
367 #ifndef QT_NO_ACTION |
|
368 |
|
369 /*! |
|
370 Creates an undo QAction object with parent \a parent. |
|
371 |
|
372 Triggering this action will cause a call to QUndoStack::undo() on the active stack. |
|
373 The text of this action will always be the text of the command which will be undone |
|
374 in the next call to undo(), prefixed by \a prefix. If there is no command available |
|
375 for undo, if the group is empty or if none of the stacks are active, this action will |
|
376 be disabled. |
|
377 |
|
378 If \a prefix is empty, the default prefix "Undo" is used. |
|
379 |
|
380 \sa createRedoAction() canUndo() QUndoCommand::text() |
|
381 */ |
|
382 |
|
383 QAction *QUndoGroup::createUndoAction(QObject *parent, const QString &prefix) const |
|
384 { |
|
385 QString pref = prefix.isEmpty() ? tr("Undo") : prefix; |
|
386 QUndoAction *result = new QUndoAction(pref, parent); |
|
387 result->setEnabled(canUndo()); |
|
388 result->setPrefixedText(undoText()); |
|
389 connect(this, SIGNAL(canUndoChanged(bool)), |
|
390 result, SLOT(setEnabled(bool))); |
|
391 connect(this, SIGNAL(undoTextChanged(QString)), |
|
392 result, SLOT(setPrefixedText(QString))); |
|
393 connect(result, SIGNAL(triggered()), this, SLOT(undo())); |
|
394 return result; |
|
395 } |
|
396 |
|
397 /*! |
|
398 Creates an redo QAction object with parent \a parent. |
|
399 |
|
400 Triggering this action will cause a call to QUndoStack::redo() on the active stack. |
|
401 The text of this action will always be the text of the command which will be redone |
|
402 in the next call to redo(), prefixed by \a prefix. If there is no command available |
|
403 for redo, if the group is empty or if none of the stacks are active, this action will |
|
404 be disabled. |
|
405 |
|
406 If \a prefix is empty, the default prefix "Undo" is used. |
|
407 |
|
408 \sa createUndoAction() canRedo() QUndoCommand::text() |
|
409 */ |
|
410 |
|
411 QAction *QUndoGroup::createRedoAction(QObject *parent, const QString &prefix) const |
|
412 { |
|
413 QString pref = prefix.isEmpty() ? tr("Redo") : prefix; |
|
414 QUndoAction *result = new QUndoAction(pref, parent); |
|
415 result->setEnabled(canRedo()); |
|
416 result->setPrefixedText(redoText()); |
|
417 connect(this, SIGNAL(canRedoChanged(bool)), |
|
418 result, SLOT(setEnabled(bool))); |
|
419 connect(this, SIGNAL(redoTextChanged(QString)), |
|
420 result, SLOT(setPrefixedText(QString))); |
|
421 connect(result, SIGNAL(triggered()), this, SLOT(redo())); |
|
422 return result; |
|
423 } |
|
424 |
|
425 #endif // QT_NO_ACTION |
|
426 |
|
427 /*! \fn void QUndoGroup::activeStackChanged(QUndoStack *stack) |
|
428 |
|
429 This signal is emitted whenever the active stack of the group changes. This can happen |
|
430 when setActiveStack() or QUndoStack::setActive() is called, or when the active stack |
|
431 is removed form the group. \a stack is the new active stack. If no stack is active, |
|
432 \a stack is 0. |
|
433 |
|
434 \sa setActiveStack() QUndoStack::setActive() |
|
435 */ |
|
436 |
|
437 /*! \fn void QUndoGroup::indexChanged(int idx) |
|
438 |
|
439 This signal is emitted whenever the active stack emits QUndoStack::indexChanged() |
|
440 or the active stack changes. |
|
441 |
|
442 \a idx is the new current index, or 0 if the active stack is 0. |
|
443 |
|
444 \sa QUndoStack::indexChanged() setActiveStack() |
|
445 */ |
|
446 |
|
447 /*! \fn void QUndoGroup::cleanChanged(bool clean) |
|
448 |
|
449 This signal is emitted whenever the active stack emits QUndoStack::cleanChanged() |
|
450 or the active stack changes. |
|
451 |
|
452 \a clean is the new state, or true if the active stack is 0. |
|
453 |
|
454 \sa QUndoStack::cleanChanged() setActiveStack() |
|
455 */ |
|
456 |
|
457 /*! \fn void QUndoGroup::canUndoChanged(bool canUndo) |
|
458 |
|
459 This signal is emitted whenever the active stack emits QUndoStack::canUndoChanged() |
|
460 or the active stack changes. |
|
461 |
|
462 \a canUndo is the new state, or false if the active stack is 0. |
|
463 |
|
464 \sa QUndoStack::canUndoChanged() setActiveStack() |
|
465 */ |
|
466 |
|
467 /*! \fn void QUndoGroup::canRedoChanged(bool canRedo) |
|
468 |
|
469 This signal is emitted whenever the active stack emits QUndoStack::canRedoChanged() |
|
470 or the active stack changes. |
|
471 |
|
472 \a canRedo is the new state, or false if the active stack is 0. |
|
473 |
|
474 \sa QUndoStack::canRedoChanged() setActiveStack() |
|
475 */ |
|
476 |
|
477 /*! \fn void QUndoGroup::undoTextChanged(const QString &undoText) |
|
478 |
|
479 This signal is emitted whenever the active stack emits QUndoStack::undoTextChanged() |
|
480 or the active stack changes. |
|
481 |
|
482 \a undoText is the new state, or an empty string if the active stack is 0. |
|
483 |
|
484 \sa QUndoStack::undoTextChanged() setActiveStack() |
|
485 */ |
|
486 |
|
487 /*! \fn void QUndoGroup::redoTextChanged(const QString &redoText) |
|
488 |
|
489 This signal is emitted whenever the active stack emits QUndoStack::redoTextChanged() |
|
490 or the active stack changes. |
|
491 |
|
492 \a redoText is the new state, or an empty string if the active stack is 0. |
|
493 |
|
494 \sa QUndoStack::redoTextChanged() setActiveStack() |
|
495 */ |
|
496 |
|
497 QT_END_NAMESPACE |
|
498 |
|
499 #endif // QT_NO_UNDOGROUP |