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