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