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

source code of qtbase/src/widgets/util/qundogroup.cpp