1 /*
2  * LibrePCB - Professional EDA for everyone!
3  * Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
4  * https://librepcb.org/
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /*******************************************************************************
21  *  Includes
22  ******************************************************************************/
23 #include "undocommandgroup.h"
24 
25 #include "scopeguardlist.h"
26 
27 #include <QtCore>
28 
29 /*******************************************************************************
30  *  Namespace
31  ******************************************************************************/
32 namespace librepcb {
33 
34 /*******************************************************************************
35  *  Constructors / Destructor
36  ******************************************************************************/
37 
UndoCommandGroup(const QString & text)38 UndoCommandGroup::UndoCommandGroup(const QString& text) noexcept
39   : UndoCommand(text) {
40 }
41 
~UndoCommandGroup()42 UndoCommandGroup::~UndoCommandGroup() noexcept {
43   // delete childs in reverse order
44   while (mChilds.count() > 0) {
45     delete mChilds.takeLast();
46   }
47 }
48 
49 /*******************************************************************************
50  *  General Methods
51  ******************************************************************************/
52 
appendChild(UndoCommand * cmd)53 bool UndoCommandGroup::appendChild(UndoCommand* cmd) {
54   // make sure "cmd" is deleted when going out of scope (e.g. because of an
55   // exception)
56   QScopedPointer<UndoCommand> cmdScopeGuard(cmd);
57 
58   if ((!cmd) || (mChilds.contains(cmd)) || (wasEverReverted())) {
59     throw LogicError(__FILE__, __LINE__);
60   }
61 
62   if (wasEverExecuted()) {
63     if (cmdScopeGuard->execute()) {  // can throw
64       mChilds.append(cmdScopeGuard.take());
65       return true;
66     } else {
67       cmdScopeGuard
68           ->undo();  // just to be sure the command has executed nothing...
69     }
70   } else {
71     mChilds.append(cmdScopeGuard.take());
72   }
73   return false;
74 }
75 
76 /*******************************************************************************
77  *  Inherited from UndoCommand
78  ******************************************************************************/
79 
performExecute()80 bool UndoCommandGroup::performExecute() {
81   bool modified = false;
82   ScopeGuardList sgl(mChilds.count());
83   for (int i = 0; i < mChilds.count(); ++i) {  // from bottom to top
84     UndoCommand* cmd = mChilds.at(i);
85     if (cmd->execute()) {
86       modified = true;
87     }
88     sgl.add([cmd]() { cmd->undo(); });
89   }
90   sgl.dismiss();
91   return modified;
92 }
93 
performUndo()94 void UndoCommandGroup::performUndo() {
95   ScopeGuardList sgl(mChilds.count());
96   for (int i = mChilds.count() - 1; i >= 0; --i) {  // from top to bottom
97     UndoCommand* cmd = mChilds.at(i);
98     cmd->undo();
99     sgl.add([cmd]() { cmd->redo(); });
100   }
101   sgl.dismiss();
102 }
103 
performRedo()104 void UndoCommandGroup::performRedo() {
105   ScopeGuardList sgl(mChilds.count());
106   for (int i = 0; i < mChilds.count(); ++i) {  // from bottom to top
107     UndoCommand* cmd = mChilds.at(i);
108     cmd->redo();
109     sgl.add([cmd]() { cmd->undo(); });
110   }
111   sgl.dismiss();
112 }
113 
114 /*******************************************************************************
115  *  Protected Methods
116  ******************************************************************************/
117 
execNewChildCmd(UndoCommand * cmd)118 void UndoCommandGroup::execNewChildCmd(UndoCommand* cmd) {
119   QScopedPointer<UndoCommand> cmdScopeGuard(cmd);
120 
121   if ((!cmd) || (mChilds.contains(cmd)) || (wasEverExecuted())) {
122     throw LogicError(__FILE__, __LINE__);
123   }
124 
125   if (cmdScopeGuard->execute()) {  // can throw
126     mChilds.append(cmdScopeGuard.take());
127   } else {
128     cmdScopeGuard
129         ->undo();  // just to be sure the command has executed nothing...
130   }
131 }
132 
133 /*******************************************************************************
134  *  End of File
135  ******************************************************************************/
136 
137 }  // namespace librepcb
138