Mercurial > hg > svcore
comparison base/CommandHistory.cpp @ 47:bac8b14ab355
* Add menu for re-adding existing layers
* Fix layer tree window so that it at least approximates correct
* Add bundled operations in command history, for use with things like
multiple consecutive changes to a parameter value
* Disambiguate plugins that happen to have identical descriptions
* Add spectral centroid plugin (could use some parameters!)
* Some other fixes
author | Chris Cannam |
---|---|
date | Fri, 17 Mar 2006 17:38:28 +0000 |
parents | 5364a9d338a2 |
children | 39ae3dee27b9 |
comparison
equal
deleted
inserted
replaced
46:5364a9d338a2 | 47:bac8b14ab355 |
---|---|
23 | 23 |
24 #include <QRegExp> | 24 #include <QRegExp> |
25 #include <QMenu> | 25 #include <QMenu> |
26 #include <QToolBar> | 26 #include <QToolBar> |
27 #include <QString> | 27 #include <QString> |
28 #include <QTimer> | |
28 | 29 |
29 #include <iostream> | 30 #include <iostream> |
30 | 31 |
31 CommandHistory *CommandHistory::m_instance = 0; | 32 CommandHistory *CommandHistory::m_instance = 0; |
32 | 33 |
33 CommandHistory::CommandHistory() : | 34 CommandHistory::CommandHistory() : |
34 m_undoLimit(50), | 35 m_undoLimit(50), |
35 m_redoLimit(50), | 36 m_redoLimit(50), |
36 m_menuLimit(15), | 37 m_menuLimit(15), |
37 m_savedAt(0), | 38 m_savedAt(0), |
38 m_currentMacro(0), | 39 m_currentCompound(0), |
39 m_executeMacro(false) | 40 m_executeCompound(false), |
41 m_currentBundle(0), | |
42 m_bundleTimer(0), | |
43 m_bundleTimeout(5000) | |
40 { | 44 { |
41 m_undoAction = new QAction(QIcon(":/icons/undo.png"), tr("&Undo"), this); | 45 m_undoAction = new QAction(QIcon(":/icons/undo.png"), tr("&Undo"), this); |
42 m_undoAction->setShortcut(tr("Ctrl+Z")); | 46 m_undoAction->setShortcut(tr("Ctrl+Z")); |
43 connect(m_undoAction, SIGNAL(triggered()), this, SLOT(undo())); | 47 connect(m_undoAction, SIGNAL(triggered()), this, SLOT(undo())); |
44 | 48 |
81 } | 85 } |
82 | 86 |
83 void | 87 void |
84 CommandHistory::clear() | 88 CommandHistory::clear() |
85 { | 89 { |
90 std::cerr << "CommandHistory::clear()" << std::endl; | |
91 closeBundle(); | |
86 m_savedAt = -1; | 92 m_savedAt = -1; |
87 clearStack(m_undoStack); | 93 clearStack(m_undoStack); |
88 clearStack(m_redoStack); | 94 clearStack(m_redoStack); |
89 updateActions(); | 95 updateActions(); |
90 } | 96 } |
102 toolbar->addAction(m_undoMenuAction); | 108 toolbar->addAction(m_undoMenuAction); |
103 toolbar->addAction(m_redoMenuAction); | 109 toolbar->addAction(m_redoMenuAction); |
104 } | 110 } |
105 | 111 |
106 void | 112 void |
107 CommandHistory::addCommand(Command *command, bool execute) | 113 CommandHistory::addCommand(Command *command, bool execute, bool bundle) |
108 { | 114 { |
109 if (!command) return; | 115 if (!command) return; |
110 | 116 |
111 if (m_currentMacro) { | 117 if (m_currentCompound) { |
112 addToMacro(command); | 118 addToCompound(command); |
113 return; | 119 return; |
114 } | 120 } |
115 | 121 |
116 std::cerr << "MVCH::addCommand: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl; | 122 if (bundle) { |
123 addToBundle(command, execute); | |
124 return; | |
125 } else if (m_currentBundle) { | |
126 closeBundle(); | |
127 } | |
128 | |
129 std::cerr << "CommandHistory::addCommand: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl; | |
117 | 130 |
118 // We can't redo after adding a command | 131 // We can't redo after adding a command |
132 std::cerr << "CommandHistory::clearing redo stack" << std::endl; | |
119 clearStack(m_redoStack); | 133 clearStack(m_redoStack); |
120 | 134 |
121 // can we reach savedAt? | 135 // can we reach savedAt? |
122 if ((int)m_undoStack.size() < m_savedAt) m_savedAt = -1; // nope | 136 if ((int)m_undoStack.size() < m_savedAt) m_savedAt = -1; // nope |
123 | 137 |
135 | 149 |
136 updateActions(); | 150 updateActions(); |
137 } | 151 } |
138 | 152 |
139 void | 153 void |
140 CommandHistory::addToMacro(Command *command) | 154 CommandHistory::addToBundle(Command *command, bool execute) |
141 { | 155 { |
142 std::cerr << "MVCH::addToMacro: " << command->getName().toLocal8Bit().data() << std::endl; | 156 if (m_currentBundle) { |
143 | 157 if (!command || (command->getName() != m_currentBundleName)) { |
144 if (m_executeMacro) command->execute(); | 158 closeBundle(); |
145 m_currentMacro->addCommand(command); | 159 } |
160 } | |
161 | |
162 if (!command) return; | |
163 | |
164 if (!m_currentBundle) { | |
165 // need to addCommand before setting m_currentBundle, as addCommand | |
166 // with bundle false will reset m_currentBundle to 0 | |
167 MacroCommand *mc = new MacroCommand(command->getName()); | |
168 addCommand(mc, false); | |
169 m_currentBundle = mc; | |
170 m_currentBundleName = command->getName(); | |
171 } | |
172 | |
173 if (execute) command->execute(); | |
174 m_currentBundle->addCommand(command); | |
175 | |
176 delete m_bundleTimer; | |
177 m_bundleTimer = new QTimer(this); | |
178 connect(m_bundleTimer, SIGNAL(timeout()), this, SLOT(bundleTimerTimeout())); | |
179 m_bundleTimer->start(m_bundleTimeout); | |
180 } | |
181 | |
182 void | |
183 CommandHistory::closeBundle() | |
184 { | |
185 m_currentBundle = 0; | |
186 m_currentBundleName = ""; | |
187 } | |
188 | |
189 void | |
190 CommandHistory::bundleTimerTimeout() | |
191 { | |
192 closeBundle(); | |
193 } | |
194 | |
195 void | |
196 CommandHistory::addToCompound(Command *command) | |
197 { | |
198 std::cerr << "CommandHistory::addToCompound: " << command->getName().toLocal8Bit().data() << std::endl; | |
199 | |
200 if (m_executeCompound) command->execute(); | |
201 m_currentCompound->addCommand(command); | |
146 } | 202 } |
147 | 203 |
148 void | 204 void |
149 CommandHistory::startCompoundOperation(QString name, bool execute) | 205 CommandHistory::startCompoundOperation(QString name, bool execute) |
150 { | 206 { |
151 if (m_currentMacro) { | 207 if (m_currentCompound) { |
152 std::cerr << "MVCH::startCompoundOperation: ERROR: compound operation already in progress!" << std::endl; | 208 std::cerr << "CommandHistory::startCompoundOperation: ERROR: compound operation already in progress!" << std::endl; |
153 std::cerr << "(name is " << m_currentMacro->getName().toLocal8Bit().data() << ")" << std::endl; | 209 std::cerr << "(name is " << m_currentCompound->getName().toLocal8Bit().data() << ")" << std::endl; |
154 } | 210 } |
155 | 211 |
156 m_currentMacro = new MacroCommand(name); | 212 closeBundle(); |
157 m_executeMacro = execute; | 213 |
214 m_currentCompound = new MacroCommand(name); | |
215 m_executeCompound = execute; | |
158 } | 216 } |
159 | 217 |
160 void | 218 void |
161 CommandHistory::endCompoundOperation() | 219 CommandHistory::endCompoundOperation() |
162 { | 220 { |
163 if (!m_currentMacro) { | 221 if (!m_currentCompound) { |
164 std::cerr << "MVCH::endCompoundOperation: ERROR: no compound operation in progress!" << std::endl; | 222 std::cerr << "CommandHistory::endCompoundOperation: ERROR: no compound operation in progress!" << std::endl; |
165 } | 223 } |
166 | 224 |
167 Command *toAdd = m_currentMacro; | 225 Command *toAdd = m_currentCompound; |
168 m_currentMacro = 0; | 226 m_currentCompound = 0; |
169 | 227 |
170 // We don't execute the macro command here, because we have been | 228 // We don't execute the macro command here, because we have been |
171 // executing the individual commands as we went along if | 229 // executing the individual commands as we went along if |
172 // m_executeMacro was true. | 230 // m_executeCompound was true. |
173 addCommand(toAdd, false); | 231 addCommand(toAdd, false); |
174 } | 232 } |
175 | 233 |
176 void | 234 void |
177 CommandHistory::addExecutedCommand(Command *command) | 235 CommandHistory::addExecutedCommand(Command *command) |
187 | 245 |
188 void | 246 void |
189 CommandHistory::undo() | 247 CommandHistory::undo() |
190 { | 248 { |
191 if (m_undoStack.empty()) return; | 249 if (m_undoStack.empty()) return; |
250 | |
251 closeBundle(); | |
192 | 252 |
193 Command *command = m_undoStack.top(); | 253 Command *command = m_undoStack.top(); |
194 command->unexecute(); | 254 command->unexecute(); |
195 emit commandExecuted(); | 255 emit commandExecuted(); |
196 emit commandUnexecuted(command); | 256 emit commandUnexecuted(command); |
207 void | 267 void |
208 CommandHistory::redo() | 268 CommandHistory::redo() |
209 { | 269 { |
210 if (m_redoStack.empty()) return; | 270 if (m_redoStack.empty()) return; |
211 | 271 |
272 closeBundle(); | |
273 | |
212 Command *command = m_redoStack.top(); | 274 Command *command = m_redoStack.top(); |
213 command->execute(); | 275 command->execute(); |
214 emit commandExecuted(); | 276 emit commandExecuted(); |
215 emit commandExecuted(command); | 277 emit commandExecuted(command); |
216 | 278 |
247 m_menuLimit = limit; | 309 m_menuLimit = limit; |
248 updateActions(); | 310 updateActions(); |
249 } | 311 } |
250 | 312 |
251 void | 313 void |
314 CommandHistory::setBundleTimeout(int ms) | |
315 { | |
316 m_bundleTimeout = ms; | |
317 } | |
318 | |
319 void | |
252 CommandHistory::documentSaved() | 320 CommandHistory::documentSaved() |
253 { | 321 { |
322 closeBundle(); | |
254 m_savedAt = m_undoStack.size(); | 323 m_savedAt = m_undoStack.size(); |
255 } | 324 } |
256 | 325 |
257 void | 326 void |
258 CommandHistory::clipCommands() | 327 CommandHistory::clipCommands() |
274 | 343 |
275 CommandStack tempStack; | 344 CommandStack tempStack; |
276 | 345 |
277 for (i = 0; i < limit; ++i) { | 346 for (i = 0; i < limit; ++i) { |
278 Command *command = stack.top(); | 347 Command *command = stack.top(); |
279 std::cerr << "MVCH::clipStack: Saving recent command: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl; | 348 std::cerr << "CommandHistory::clipStack: Saving recent command: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl; |
280 tempStack.push(stack.top()); | 349 tempStack.push(stack.top()); |
281 stack.pop(); | 350 stack.pop(); |
282 } | 351 } |
283 | 352 |
284 clearStack(stack); | 353 clearStack(stack); |
294 CommandHistory::clearStack(CommandStack &stack) | 363 CommandHistory::clearStack(CommandStack &stack) |
295 { | 364 { |
296 while (!stack.empty()) { | 365 while (!stack.empty()) { |
297 Command *command = stack.top(); | 366 Command *command = stack.top(); |
298 // Not safe to call getName() on a command about to be deleted | 367 // Not safe to call getName() on a command about to be deleted |
299 std::cerr << "MVCH::clearStack: About to delete command " << command << std::endl; | 368 std::cerr << "CommandHistory::clearStack: About to delete command " << command << std::endl; |
300 delete command; | 369 delete command; |
301 stack.pop(); | 370 stack.pop(); |
302 } | 371 } |
303 } | 372 } |
304 | 373 |