annotate widgets/CommandHistory.cpp @ 959:2633a1d73e39

Address #1214, layer import produces wrong layer type. We needed a more principled approach to making sure the format gets updated properly and the dialog elements are consistent (basically separating making the dialog elements consistent from subsequently updating the format). This change should provide that, though there may be gotchas still.
author Chris Cannam
date Tue, 12 May 2015 12:31:37 +0100
parents 4a578a360011
children c91878670297
rev   line source
Chris@376 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@376 2
Chris@376 3 /*
Chris@376 4 Sonic Visualiser
Chris@376 5 An audio file viewer and annotation editor.
Chris@376 6 Centre for Digital Music, Queen Mary, University of London.
Chris@376 7
Chris@376 8 This program is free software; you can redistribute it and/or
Chris@376 9 modify it under the terms of the GNU General Public License as
Chris@376 10 published by the Free Software Foundation; either version 2 of the
Chris@376 11 License, or (at your option) any later version. See the file
Chris@376 12 COPYING included with this distribution for more information.
Chris@376 13 */
Chris@376 14
Chris@376 15 /*
Chris@376 16 This is a modified version of a source file from the Rosegarden
Chris@376 17 MIDI and audio sequencer and notation editor, copyright 2000-2006
Chris@376 18 Chris Cannam, distributed under the GNU General Public License.
Chris@376 19
Chris@376 20 This file contains traces of the KCommandHistory class from the KDE
Chris@376 21 project, copyright 2000 Werner Trobin and David Faure and
Chris@376 22 distributed under the GNU Lesser General Public License.
Chris@376 23 */
Chris@376 24
Chris@376 25 #include "CommandHistory.h"
Chris@376 26
Chris@376 27 #include "base/Command.h"
Chris@376 28
Chris@376 29 #include <QRegExp>
Chris@376 30 #include <QMenu>
Chris@376 31 #include <QToolBar>
Chris@376 32 #include <QString>
Chris@376 33 #include <QTimer>
Chris@376 34 #include <QAction>
Chris@376 35
Chris@376 36 #include <iostream>
Chris@376 37
Chris@503 38 #include <typeinfo>
Chris@503 39
Chris@800 40 //#define DEBUG_COMMAND_HISTORY 1
Chris@377 41
Chris@376 42 CommandHistory *CommandHistory::m_instance = 0;
Chris@376 43
Chris@376 44 CommandHistory::CommandHistory() :
Chris@376 45 m_undoLimit(50),
Chris@376 46 m_redoLimit(50),
Chris@376 47 m_menuLimit(15),
Chris@376 48 m_savedAt(0),
Chris@376 49 m_currentCompound(0),
Chris@376 50 m_executeCompound(false),
Chris@376 51 m_currentBundle(0),
Chris@502 52 m_bundling(false),
Chris@376 53 m_bundleTimer(0),
Chris@502 54 m_bundleTimeout(3000)
Chris@376 55 {
Chris@376 56 m_undoAction = new QAction(QIcon(":/icons/undo.png"), tr("&Undo"), this);
Chris@376 57 m_undoAction->setShortcut(tr("Ctrl+Z"));
Chris@376 58 m_undoAction->setStatusTip(tr("Undo the last editing operation"));
Chris@376 59 connect(m_undoAction, SIGNAL(triggered()), this, SLOT(undo()));
Chris@376 60
Chris@376 61 m_undoMenuAction = new QAction(QIcon(":/icons/undo.png"), tr("&Undo"), this);
Chris@376 62 connect(m_undoMenuAction, SIGNAL(triggered()), this, SLOT(undo()));
Chris@376 63
Chris@376 64 m_undoMenu = new QMenu(tr("&Undo"));
Chris@376 65 m_undoMenuAction->setMenu(m_undoMenu);
Chris@376 66 connect(m_undoMenu, SIGNAL(triggered(QAction *)),
Chris@376 67 this, SLOT(undoActivated(QAction*)));
Chris@376 68
Chris@376 69 m_redoAction = new QAction(QIcon(":/icons/redo.png"), tr("Re&do"), this);
Chris@376 70 m_redoAction->setShortcut(tr("Ctrl+Shift+Z"));
Chris@376 71 m_redoAction->setStatusTip(tr("Redo the last operation that was undone"));
Chris@376 72 connect(m_redoAction, SIGNAL(triggered()), this, SLOT(redo()));
Chris@376 73
Chris@376 74 m_redoMenuAction = new QAction(QIcon(":/icons/redo.png"), tr("Re&do"), this);
Chris@376 75 connect(m_redoMenuAction, SIGNAL(triggered()), this, SLOT(redo()));
Chris@376 76
Chris@376 77 m_redoMenu = new QMenu(tr("Re&do"));
Chris@376 78 m_redoMenuAction->setMenu(m_redoMenu);
Chris@376 79 connect(m_redoMenu, SIGNAL(triggered(QAction *)),
Chris@376 80 this, SLOT(redoActivated(QAction*)));
Chris@376 81 }
Chris@376 82
Chris@376 83 CommandHistory::~CommandHistory()
Chris@376 84 {
Chris@376 85 m_savedAt = -1;
Chris@376 86 clearStack(m_undoStack);
Chris@376 87 clearStack(m_redoStack);
Chris@376 88
Chris@376 89 delete m_undoMenu;
Chris@376 90 delete m_redoMenu;
Chris@376 91 }
Chris@376 92
Chris@376 93 CommandHistory *
Chris@376 94 CommandHistory::getInstance()
Chris@376 95 {
Chris@376 96 if (!m_instance) m_instance = new CommandHistory();
Chris@376 97 return m_instance;
Chris@376 98 }
Chris@376 99
Chris@376 100 void
Chris@376 101 CommandHistory::clear()
Chris@376 102 {
Chris@377 103 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 104 cerr << "CommandHistory::clear()" << endl;
Chris@377 105 #endif
Chris@376 106 closeBundle();
Chris@376 107 m_savedAt = -1;
Chris@376 108 clearStack(m_undoStack);
Chris@376 109 clearStack(m_redoStack);
Chris@376 110 updateActions();
Chris@376 111 }
Chris@376 112
Chris@376 113 void
Chris@376 114 CommandHistory::registerMenu(QMenu *menu)
Chris@376 115 {
Chris@376 116 menu->addAction(m_undoAction);
Chris@376 117 menu->addAction(m_redoAction);
Chris@376 118 }
Chris@376 119
Chris@376 120 void
Chris@376 121 CommandHistory::registerToolbar(QToolBar *toolbar)
Chris@376 122 {
Chris@376 123 toolbar->addAction(m_undoMenuAction);
Chris@376 124 toolbar->addAction(m_redoMenuAction);
Chris@376 125 }
Chris@376 126
Chris@376 127 void
Chris@376 128 CommandHistory::addCommand(Command *command)
Chris@376 129 {
Chris@376 130 if (!command) return;
Chris@376 131
Chris@376 132 if (m_currentCompound) {
Chris@376 133 addToCompound(command, m_executeCompound);
Chris@376 134 return;
Chris@376 135 }
Chris@376 136
Chris@376 137 addCommand(command, true);
Chris@376 138 }
Chris@376 139
Chris@376 140 void
Chris@376 141 CommandHistory::addCommand(Command *command, bool execute, bool bundle)
Chris@376 142 {
Chris@376 143 if (!command) return;
Chris@376 144
Chris@397 145 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 146 cerr << "CommandHistory::addCommand: " << command->getName() << " of type " << typeid(*command).name() << " at " << command << ": execute = " << execute << ", bundle = " << bundle << " (m_currentCompound = " << m_currentCompound << ", m_currentBundle = " << m_currentBundle << ")" << endl;
Chris@397 147 #endif
Chris@397 148
Chris@376 149 if (m_currentCompound) {
Chris@376 150 addToCompound(command, execute);
Chris@376 151 return;
Chris@376 152 }
Chris@376 153
Chris@376 154 if (bundle) {
Chris@376 155 addToBundle(command, execute);
Chris@376 156 return;
Chris@376 157 } else if (m_currentBundle) {
Chris@376 158 closeBundle();
Chris@376 159 }
Chris@376 160
Chris@377 161 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 162 if (!m_redoStack.empty()) {
Chris@752 163 cerr << "CommandHistory::clearing redo stack" << endl;
Chris@377 164 }
Chris@377 165 #endif
Chris@376 166
Chris@376 167 // We can't redo after adding a command
Chris@376 168 clearStack(m_redoStack);
Chris@376 169
Chris@376 170 // can we reach savedAt?
Chris@376 171 if ((int)m_undoStack.size() < m_savedAt) m_savedAt = -1; // nope
Chris@376 172
Chris@376 173 m_undoStack.push(command);
Chris@376 174 clipCommands();
Chris@376 175
Chris@376 176 if (execute) {
Chris@376 177 command->execute();
Chris@376 178 }
Chris@376 179
Chris@376 180 // Emit even if we aren't executing the command, because
Chris@376 181 // someone must have executed it for this to make any sense
Chris@376 182 emit commandExecuted();
Chris@376 183 emit commandExecuted(command);
Chris@502 184 if (!m_bundling) emit activity(command->getName());
Chris@502 185
Chris@376 186 updateActions();
Chris@376 187 }
Chris@376 188
Chris@376 189 void
Chris@376 190 CommandHistory::addToBundle(Command *command, bool execute)
Chris@376 191 {
Chris@376 192 if (m_currentBundle) {
Chris@376 193 if (!command || (command->getName() != m_currentBundleName)) {
Chris@377 194 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 195 cerr << "CommandHistory::addToBundle: " << command->getName()
Chris@752 196 << ": closing current bundle" << endl;
Chris@377 197 #endif
Chris@376 198 closeBundle();
Chris@376 199 }
Chris@376 200 }
Chris@376 201
Chris@376 202 if (!command) return;
Chris@376 203
Chris@376 204 if (!m_currentBundle) {
Chris@377 205
Chris@377 206 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 207 cerr << "CommandHistory::addToBundle: " << command->getName()
Chris@752 208 << ": creating new bundle" << endl;
Chris@377 209 #endif
Chris@377 210
Chris@376 211 // need to addCommand before setting m_currentBundle, as addCommand
Chris@376 212 // with bundle false will reset m_currentBundle to 0
Chris@397 213 MacroCommand *mc = new BundleCommand(command->getName());
Chris@502 214 m_bundling = true;
Chris@376 215 addCommand(mc, false);
Chris@502 216 m_bundling = false;
Chris@376 217 m_currentBundle = mc;
Chris@376 218 m_currentBundleName = command->getName();
Chris@376 219 }
Chris@376 220
Chris@377 221 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 222 cerr << "CommandHistory::addToBundle: " << command->getName()
Chris@752 223 << ": adding to bundle" << endl;
Chris@377 224 #endif
Chris@377 225
Chris@376 226 if (execute) command->execute();
Chris@376 227 m_currentBundle->addCommand(command);
Chris@376 228
Chris@377 229 // Emit even if we aren't executing the command, because
Chris@377 230 // someone must have executed it for this to make any sense
Chris@377 231 emit commandExecuted();
Chris@377 232 emit commandExecuted(command);
Chris@377 233
Chris@377 234 updateActions();
Chris@377 235
Chris@376 236 delete m_bundleTimer;
Chris@376 237 m_bundleTimer = new QTimer(this);
Chris@376 238 connect(m_bundleTimer, SIGNAL(timeout()), this, SLOT(bundleTimerTimeout()));
Chris@376 239 m_bundleTimer->start(m_bundleTimeout);
Chris@376 240 }
Chris@376 241
Chris@376 242 void
Chris@376 243 CommandHistory::closeBundle()
Chris@376 244 {
Chris@752 245 if (m_currentBundle) {
Chris@377 246 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 247 cerr << "CommandHistory::closeBundle" << endl;
Chris@377 248 #endif
Chris@752 249 emit activity(m_currentBundle->getName());
Chris@752 250 }
Chris@376 251 m_currentBundle = 0;
Chris@376 252 m_currentBundleName = "";
Chris@376 253 }
Chris@376 254
Chris@376 255 void
Chris@376 256 CommandHistory::bundleTimerTimeout()
Chris@376 257 {
Chris@377 258 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 259 cerr << "CommandHistory::bundleTimerTimeout: bundle is " << m_currentBundle << endl;
Chris@377 260 #endif
Chris@377 261
Chris@376 262 closeBundle();
Chris@376 263 }
Chris@376 264
Chris@376 265 void
Chris@376 266 CommandHistory::addToCompound(Command *command, bool execute)
Chris@376 267 {
Chris@376 268 if (!m_currentCompound) {
Chris@752 269 cerr << "CommandHistory::addToCompound: ERROR: no compound operation in progress!" << endl;
Chris@376 270 return;
Chris@376 271 }
Chris@376 272
Chris@752 273 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 274 cerr << "CommandHistory::addToCompound[" << m_currentCompound->getName() << "]: " << command->getName() << " (exec: " << execute << ")" << endl;
Chris@752 275 #endif
Chris@752 276
Chris@376 277 if (execute) command->execute();
Chris@376 278 m_currentCompound->addCommand(command);
Chris@376 279 }
Chris@376 280
Chris@376 281 void
Chris@376 282 CommandHistory::startCompoundOperation(QString name, bool execute)
Chris@376 283 {
Chris@376 284 if (m_currentCompound) {
Chris@752 285 cerr << "CommandHistory::startCompoundOperation: ERROR: compound operation already in progress!" << endl;
Chris@683 286 cerr << "(name is " << m_currentCompound->getName() << ")" << endl;
Chris@376 287 return;
Chris@376 288 }
Chris@376 289
Chris@752 290 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 291 cerr << "CommandHistory::startCompoundOperation: " << name << " (exec: " << execute << ")" << endl;
Chris@752 292 #endif
Chris@752 293
Chris@376 294 closeBundle();
Chris@752 295
Chris@376 296 m_currentCompound = new MacroCommand(name);
Chris@376 297 m_executeCompound = execute;
Chris@376 298 }
Chris@376 299
Chris@376 300 void
Chris@376 301 CommandHistory::endCompoundOperation()
Chris@376 302 {
Chris@376 303 if (!m_currentCompound) {
Chris@752 304 cerr << "CommandHistory::endCompoundOperation: ERROR: no compound operation in progress!" << endl;
Chris@376 305 return;
Chris@376 306 }
Chris@752 307
Chris@752 308 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 309 cerr << "CommandHistory::endCompoundOperation: " << m_currentCompound->getName() << endl;
Chris@752 310 #endif
Chris@376 311
Chris@376 312 MacroCommand *toAdd = m_currentCompound;
Chris@376 313 m_currentCompound = 0;
Chris@376 314
Chris@376 315 if (toAdd->haveCommands()) {
Chris@376 316
Chris@376 317 // We don't execute the macro command here, because we have
Chris@376 318 // been executing the individual commands as we went along if
Chris@376 319 // m_executeCompound was true.
Chris@376 320 addCommand(toAdd, false);
Chris@376 321 }
Chris@376 322 }
Chris@376 323
Chris@376 324 void
Chris@376 325 CommandHistory::addExecutedCommand(Command *command)
Chris@376 326 {
Chris@376 327 addCommand(command, false);
Chris@376 328 }
Chris@376 329
Chris@376 330 void
Chris@376 331 CommandHistory::addCommandAndExecute(Command *command)
Chris@376 332 {
Chris@376 333 addCommand(command, true);
Chris@376 334 }
Chris@376 335
Chris@376 336 void
Chris@376 337 CommandHistory::undo()
Chris@376 338 {
Chris@376 339 if (m_undoStack.empty()) return;
Chris@376 340
Chris@377 341 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 342 cerr << "CommandHistory::undo()" << endl;
Chris@377 343 #endif
Chris@377 344
Chris@376 345 closeBundle();
Chris@376 346
Chris@376 347 Command *command = m_undoStack.top();
Chris@376 348 command->unexecute();
Chris@376 349 emit commandExecuted();
Chris@376 350 emit commandUnexecuted(command);
Chris@502 351 emit activity(tr("Undo %1").arg(command->getName()));
Chris@376 352
Chris@376 353 m_redoStack.push(command);
Chris@376 354 m_undoStack.pop();
Chris@376 355
Chris@376 356 clipCommands();
Chris@376 357 updateActions();
Chris@376 358
Chris@376 359 if ((int)m_undoStack.size() == m_savedAt) emit documentRestored();
Chris@376 360 }
Chris@376 361
Chris@376 362 void
Chris@376 363 CommandHistory::redo()
Chris@376 364 {
Chris@376 365 if (m_redoStack.empty()) return;
Chris@376 366
Chris@377 367 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 368 cerr << "CommandHistory::redo()" << endl;
Chris@377 369 #endif
Chris@377 370
Chris@376 371 closeBundle();
Chris@376 372
Chris@376 373 Command *command = m_redoStack.top();
Chris@376 374 command->execute();
Chris@376 375 emit commandExecuted();
Chris@376 376 emit commandExecuted(command);
Chris@502 377 emit activity(tr("Redo %1").arg(command->getName()));
Chris@376 378
Chris@376 379 m_undoStack.push(command);
Chris@376 380 m_redoStack.pop();
Chris@376 381 // no need to clip
Chris@376 382
Chris@376 383 updateActions();
Chris@376 384
Chris@376 385 if ((int)m_undoStack.size() == m_savedAt) emit documentRestored();
Chris@376 386 }
Chris@376 387
Chris@376 388 void
Chris@376 389 CommandHistory::setUndoLimit(int limit)
Chris@376 390 {
Chris@376 391 if (limit > 0 && limit != m_undoLimit) {
Chris@376 392 m_undoLimit = limit;
Chris@376 393 clipCommands();
Chris@376 394 }
Chris@376 395 }
Chris@376 396
Chris@376 397 void
Chris@376 398 CommandHistory::setRedoLimit(int limit)
Chris@376 399 {
Chris@376 400 if (limit > 0 && limit != m_redoLimit) {
Chris@376 401 m_redoLimit = limit;
Chris@376 402 clipCommands();
Chris@376 403 }
Chris@376 404 }
Chris@376 405
Chris@376 406 void
Chris@376 407 CommandHistory::setMenuLimit(int limit)
Chris@376 408 {
Chris@376 409 m_menuLimit = limit;
Chris@376 410 updateActions();
Chris@376 411 }
Chris@376 412
Chris@376 413 void
Chris@376 414 CommandHistory::setBundleTimeout(int ms)
Chris@376 415 {
Chris@376 416 m_bundleTimeout = ms;
Chris@376 417 }
Chris@376 418
Chris@376 419 void
Chris@376 420 CommandHistory::documentSaved()
Chris@376 421 {
Chris@376 422 closeBundle();
Chris@908 423 m_savedAt = int(m_undoStack.size());
Chris@376 424 }
Chris@376 425
Chris@376 426 void
Chris@376 427 CommandHistory::clipCommands()
Chris@376 428 {
Chris@908 429 if (int(m_undoStack.size()) > m_undoLimit) {
Chris@908 430 m_savedAt -= (int(m_undoStack.size()) - m_undoLimit);
Chris@376 431 }
Chris@376 432
Chris@376 433 clipStack(m_undoStack, m_undoLimit);
Chris@376 434 clipStack(m_redoStack, m_redoLimit);
Chris@376 435 }
Chris@376 436
Chris@376 437 void
Chris@376 438 CommandHistory::clipStack(CommandStack &stack, int limit)
Chris@376 439 {
Chris@376 440 int i;
Chris@376 441
Chris@376 442 if ((int)stack.size() > limit) {
Chris@376 443
Chris@376 444 CommandStack tempStack;
Chris@376 445
Chris@376 446 for (i = 0; i < limit; ++i) {
Chris@377 447 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 448 Command *command = stack.top();
Chris@752 449 cerr << "CommandHistory::clipStack: Saving recent command: " << command->getName() << " at " << command << endl;
Chris@377 450 #endif
Chris@376 451 tempStack.push(stack.top());
Chris@376 452 stack.pop();
Chris@376 453 }
Chris@376 454
Chris@376 455 clearStack(stack);
Chris@376 456
Chris@376 457 for (i = 0; i < m_undoLimit; ++i) {
Chris@376 458 stack.push(tempStack.top());
Chris@376 459 tempStack.pop();
Chris@376 460 }
Chris@376 461 }
Chris@376 462 }
Chris@376 463
Chris@376 464 void
Chris@376 465 CommandHistory::clearStack(CommandStack &stack)
Chris@376 466 {
Chris@376 467 while (!stack.empty()) {
Chris@376 468 Command *command = stack.top();
Chris@376 469 // Not safe to call getName() on a command about to be deleted
Chris@377 470 #ifdef DEBUG_COMMAND_HISTORY
Chris@752 471 cerr << "CommandHistory::clearStack: About to delete command " << command << endl;
Chris@377 472 #endif
Chris@376 473 delete command;
Chris@376 474 stack.pop();
Chris@376 475 }
Chris@376 476 }
Chris@376 477
Chris@376 478 void
Chris@376 479 CommandHistory::undoActivated(QAction *action)
Chris@376 480 {
Chris@376 481 int pos = m_actionCounts[action];
Chris@376 482 for (int i = 0; i <= pos; ++i) {
Chris@376 483 undo();
Chris@376 484 }
Chris@376 485 }
Chris@376 486
Chris@376 487 void
Chris@376 488 CommandHistory::redoActivated(QAction *action)
Chris@376 489 {
Chris@376 490 int pos = m_actionCounts[action];
Chris@376 491 for (int i = 0; i <= pos; ++i) {
Chris@376 492 redo();
Chris@376 493 }
Chris@376 494 }
Chris@376 495
Chris@376 496 void
Chris@376 497 CommandHistory::updateActions()
Chris@376 498 {
Chris@376 499 m_actionCounts.clear();
Chris@376 500
Chris@376 501 for (int undo = 0; undo <= 1; ++undo) {
Chris@376 502
Chris@376 503 QAction *action(undo ? m_undoAction : m_redoAction);
Chris@376 504 QAction *menuAction(undo ? m_undoMenuAction : m_redoMenuAction);
Chris@376 505 QMenu *menu(undo ? m_undoMenu : m_redoMenu);
Chris@376 506 CommandStack &stack(undo ? m_undoStack : m_redoStack);
Chris@376 507
Chris@376 508 if (stack.empty()) {
Chris@376 509
Chris@376 510 QString text(undo ? tr("Nothing to undo") : tr("Nothing to redo"));
Chris@376 511
Chris@376 512 action->setEnabled(false);
Chris@376 513 action->setText(text);
Chris@376 514
Chris@376 515 menuAction->setEnabled(false);
Chris@376 516 menuAction->setText(text);
Chris@376 517
Chris@376 518 } else {
Chris@376 519
Chris@376 520 action->setEnabled(true);
Chris@376 521 menuAction->setEnabled(true);
Chris@376 522
Chris@376 523 QString commandName = stack.top()->getName();
Chris@376 524 commandName.replace(QRegExp("&"), "");
Chris@376 525
Chris@376 526 QString text = (undo ? tr("&Undo %1") : tr("Re&do %1"))
Chris@376 527 .arg(commandName);
Chris@376 528
Chris@376 529 action->setText(text);
Chris@376 530 menuAction->setText(text);
Chris@376 531 }
Chris@376 532
Chris@376 533 menu->clear();
Chris@376 534
Chris@376 535 CommandStack tempStack;
Chris@376 536 int j = 0;
Chris@376 537
Chris@376 538 while (j < m_menuLimit && !stack.empty()) {
Chris@376 539
Chris@376 540 Command *command = stack.top();
Chris@376 541 tempStack.push(command);
Chris@376 542 stack.pop();
Chris@376 543
Chris@376 544 QString commandName = command->getName();
Chris@376 545 commandName.replace(QRegExp("&"), "");
Chris@376 546
Chris@376 547 QString text;
Chris@376 548 if (undo) text = tr("&Undo %1").arg(commandName);
Chris@376 549 else text = tr("Re&do %1").arg(commandName);
Chris@376 550
Chris@376 551 QAction *action = menu->addAction(text);
Chris@376 552 m_actionCounts[action] = j++;
Chris@376 553 }
Chris@376 554
Chris@376 555 while (!tempStack.empty()) {
Chris@376 556 stack.push(tempStack.top());
Chris@376 557 tempStack.pop();
Chris@376 558 }
Chris@376 559 }
Chris@376 560 }
Chris@376 561