annotate widgets/CommandHistory.cpp @ 899:b70addc910d5 datarace

Enable ThreadSanitizer
author Chris Cannam
date Tue, 24 Feb 2015 17:42:00 +0000
parents 102ffad481e6
children 4a578a360011
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@376 423 m_savedAt = m_undoStack.size();
Chris@376 424 }
Chris@376 425
Chris@376 426 void
Chris@376 427 CommandHistory::clipCommands()
Chris@376 428 {
Chris@376 429 if ((int)m_undoStack.size() > m_undoLimit) {
Chris@376 430 m_savedAt -= (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