annotate widgets/CommandHistory.cpp @ 561:aced8ec09bc8

* Complete the overhaul of CSV file import; now you can pick the purpose for each column in the file, and SV should do the rest. The most significant practical improvement here is that we can now handle files in which time and duration do not necessarily appear in known columns.
author Chris Cannam
date Mon, 19 Jul 2010 17:08:56 +0000
parents 4ba0476ebbb6
children f4960f8ce798
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@514 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@377 104 std::cerr << "CommandHistory::clear()" << std::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@503 146 std::cerr << "CommandHistory::addCommand: " << command->getName().toLocal8Bit().data() << " of type " << typeid(*command).name() << " at " << command << ": execute = " << execute << ", bundle = " << bundle << " (m_currentCompound = " << m_currentCompound << ", m_currentBundle = " << m_currentBundle << ")" << std::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@377 163 std::cerr << "CommandHistory::clearing redo stack" << std::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@377 195 std::cerr << "CommandHistory::addToBundle: "
Chris@377 196 << command->getName().toStdString()
Chris@377 197 << ": closing current bundle" << std::endl;
Chris@377 198 #endif
Chris@376 199 closeBundle();
Chris@376 200 }
Chris@376 201 }
Chris@376 202
Chris@376 203 if (!command) return;
Chris@376 204
Chris@376 205 if (!m_currentBundle) {
Chris@377 206
Chris@377 207 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 208 std::cerr << "CommandHistory::addToBundle: "
Chris@377 209 << command->getName().toStdString()
Chris@377 210 << ": creating new bundle" << std::endl;
Chris@377 211 #endif
Chris@377 212
Chris@376 213 // need to addCommand before setting m_currentBundle, as addCommand
Chris@376 214 // with bundle false will reset m_currentBundle to 0
Chris@397 215 MacroCommand *mc = new BundleCommand(command->getName());
Chris@502 216 m_bundling = true;
Chris@376 217 addCommand(mc, false);
Chris@502 218 m_bundling = false;
Chris@376 219 m_currentBundle = mc;
Chris@376 220 m_currentBundleName = command->getName();
Chris@376 221 }
Chris@376 222
Chris@377 223 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 224 std::cerr << "CommandHistory::addToBundle: "
Chris@377 225 << command->getName().toStdString()
Chris@377 226 << ": adding to bundle" << std::endl;
Chris@377 227 #endif
Chris@377 228
Chris@376 229 if (execute) command->execute();
Chris@376 230 m_currentBundle->addCommand(command);
Chris@376 231
Chris@377 232 // Emit even if we aren't executing the command, because
Chris@377 233 // someone must have executed it for this to make any sense
Chris@377 234 emit commandExecuted();
Chris@377 235 emit commandExecuted(command);
Chris@377 236
Chris@377 237 updateActions();
Chris@377 238
Chris@376 239 delete m_bundleTimer;
Chris@376 240 m_bundleTimer = new QTimer(this);
Chris@376 241 connect(m_bundleTimer, SIGNAL(timeout()), this, SLOT(bundleTimerTimeout()));
Chris@376 242 m_bundleTimer->start(m_bundleTimeout);
Chris@376 243 }
Chris@376 244
Chris@376 245 void
Chris@376 246 CommandHistory::closeBundle()
Chris@376 247 {
Chris@377 248 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 249 std::cerr << "CommandHistory::closeBundle" << std::endl;
Chris@377 250 #endif
Chris@377 251
Chris@502 252 if (m_currentBundle) emit activity(m_currentBundle->getName());
Chris@376 253 m_currentBundle = 0;
Chris@376 254 m_currentBundleName = "";
Chris@376 255 }
Chris@376 256
Chris@376 257 void
Chris@376 258 CommandHistory::bundleTimerTimeout()
Chris@376 259 {
Chris@377 260 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 261 std::cerr << "CommandHistory::bundleTimerTimeout: bundle is " << m_currentBundle << std::endl;
Chris@377 262 #endif
Chris@377 263
Chris@376 264 closeBundle();
Chris@376 265 }
Chris@376 266
Chris@376 267 void
Chris@376 268 CommandHistory::addToCompound(Command *command, bool execute)
Chris@376 269 {
Chris@377 270 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 271 std::cerr << "CommandHistory::addToCompound: " << command->getName().toLocal8Bit().data() << std::endl;
Chris@377 272 #endif
Chris@376 273 if (!m_currentCompound) {
Chris@376 274 std::cerr << "CommandHistory::addToCompound: ERROR: no compound operation in progress!" << std::endl;
Chris@376 275 return;
Chris@376 276 }
Chris@376 277
Chris@376 278 if (execute) command->execute();
Chris@376 279 m_currentCompound->addCommand(command);
Chris@376 280 }
Chris@376 281
Chris@376 282 void
Chris@376 283 CommandHistory::startCompoundOperation(QString name, bool execute)
Chris@376 284 {
Chris@376 285 if (m_currentCompound) {
Chris@376 286 std::cerr << "CommandHistory::startCompoundOperation: ERROR: compound operation already in progress!" << std::endl;
Chris@376 287 std::cerr << "(name is " << m_currentCompound->getName().toLocal8Bit().data() << ")" << std::endl;
Chris@376 288 return;
Chris@376 289 }
Chris@376 290
Chris@376 291 closeBundle();
Chris@376 292
Chris@376 293 m_currentCompound = new MacroCommand(name);
Chris@376 294 m_executeCompound = execute;
Chris@376 295 }
Chris@376 296
Chris@376 297 void
Chris@376 298 CommandHistory::endCompoundOperation()
Chris@376 299 {
Chris@376 300 if (!m_currentCompound) {
Chris@376 301 std::cerr << "CommandHistory::endCompoundOperation: ERROR: no compound operation in progress!" << std::endl;
Chris@376 302 return;
Chris@376 303 }
Chris@376 304
Chris@376 305 MacroCommand *toAdd = m_currentCompound;
Chris@376 306 m_currentCompound = 0;
Chris@376 307
Chris@376 308 if (toAdd->haveCommands()) {
Chris@376 309
Chris@376 310 // We don't execute the macro command here, because we have
Chris@376 311 // been executing the individual commands as we went along if
Chris@376 312 // m_executeCompound was true.
Chris@376 313 addCommand(toAdd, false);
Chris@376 314 }
Chris@376 315 }
Chris@376 316
Chris@376 317 void
Chris@376 318 CommandHistory::addExecutedCommand(Command *command)
Chris@376 319 {
Chris@376 320 addCommand(command, false);
Chris@376 321 }
Chris@376 322
Chris@376 323 void
Chris@376 324 CommandHistory::addCommandAndExecute(Command *command)
Chris@376 325 {
Chris@376 326 addCommand(command, true);
Chris@376 327 }
Chris@376 328
Chris@376 329 void
Chris@376 330 CommandHistory::undo()
Chris@376 331 {
Chris@376 332 if (m_undoStack.empty()) return;
Chris@376 333
Chris@377 334 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 335 std::cerr << "CommandHistory::undo()" << std::endl;
Chris@377 336 #endif
Chris@377 337
Chris@376 338 closeBundle();
Chris@376 339
Chris@376 340 Command *command = m_undoStack.top();
Chris@376 341 command->unexecute();
Chris@376 342 emit commandExecuted();
Chris@376 343 emit commandUnexecuted(command);
Chris@502 344 emit activity(tr("Undo %1").arg(command->getName()));
Chris@376 345
Chris@376 346 m_redoStack.push(command);
Chris@376 347 m_undoStack.pop();
Chris@376 348
Chris@376 349 clipCommands();
Chris@376 350 updateActions();
Chris@376 351
Chris@376 352 if ((int)m_undoStack.size() == m_savedAt) emit documentRestored();
Chris@376 353 }
Chris@376 354
Chris@376 355 void
Chris@376 356 CommandHistory::redo()
Chris@376 357 {
Chris@376 358 if (m_redoStack.empty()) return;
Chris@376 359
Chris@377 360 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 361 std::cerr << "CommandHistory::redo()" << std::endl;
Chris@377 362 #endif
Chris@377 363
Chris@376 364 closeBundle();
Chris@376 365
Chris@376 366 Command *command = m_redoStack.top();
Chris@376 367 command->execute();
Chris@376 368 emit commandExecuted();
Chris@376 369 emit commandExecuted(command);
Chris@502 370 emit activity(tr("Redo %1").arg(command->getName()));
Chris@376 371
Chris@376 372 m_undoStack.push(command);
Chris@376 373 m_redoStack.pop();
Chris@376 374 // no need to clip
Chris@376 375
Chris@376 376 updateActions();
Chris@376 377
Chris@376 378 if ((int)m_undoStack.size() == m_savedAt) emit documentRestored();
Chris@376 379 }
Chris@376 380
Chris@376 381 void
Chris@376 382 CommandHistory::setUndoLimit(int limit)
Chris@376 383 {
Chris@376 384 if (limit > 0 && limit != m_undoLimit) {
Chris@376 385 m_undoLimit = limit;
Chris@376 386 clipCommands();
Chris@376 387 }
Chris@376 388 }
Chris@376 389
Chris@376 390 void
Chris@376 391 CommandHistory::setRedoLimit(int limit)
Chris@376 392 {
Chris@376 393 if (limit > 0 && limit != m_redoLimit) {
Chris@376 394 m_redoLimit = limit;
Chris@376 395 clipCommands();
Chris@376 396 }
Chris@376 397 }
Chris@376 398
Chris@376 399 void
Chris@376 400 CommandHistory::setMenuLimit(int limit)
Chris@376 401 {
Chris@376 402 m_menuLimit = limit;
Chris@376 403 updateActions();
Chris@376 404 }
Chris@376 405
Chris@376 406 void
Chris@376 407 CommandHistory::setBundleTimeout(int ms)
Chris@376 408 {
Chris@376 409 m_bundleTimeout = ms;
Chris@376 410 }
Chris@376 411
Chris@376 412 void
Chris@376 413 CommandHistory::documentSaved()
Chris@376 414 {
Chris@376 415 closeBundle();
Chris@376 416 m_savedAt = m_undoStack.size();
Chris@376 417 }
Chris@376 418
Chris@376 419 void
Chris@376 420 CommandHistory::clipCommands()
Chris@376 421 {
Chris@376 422 if ((int)m_undoStack.size() > m_undoLimit) {
Chris@376 423 m_savedAt -= (m_undoStack.size() - m_undoLimit);
Chris@376 424 }
Chris@376 425
Chris@376 426 clipStack(m_undoStack, m_undoLimit);
Chris@376 427 clipStack(m_redoStack, m_redoLimit);
Chris@376 428 }
Chris@376 429
Chris@376 430 void
Chris@376 431 CommandHistory::clipStack(CommandStack &stack, int limit)
Chris@376 432 {
Chris@376 433 int i;
Chris@376 434
Chris@376 435 if ((int)stack.size() > limit) {
Chris@376 436
Chris@376 437 CommandStack tempStack;
Chris@376 438
Chris@376 439 for (i = 0; i < limit; ++i) {
Chris@377 440 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 441 Command *command = stack.top();
Chris@377 442 std::cerr << "CommandHistory::clipStack: Saving recent command: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl;
Chris@377 443 #endif
Chris@376 444 tempStack.push(stack.top());
Chris@376 445 stack.pop();
Chris@376 446 }
Chris@376 447
Chris@376 448 clearStack(stack);
Chris@376 449
Chris@376 450 for (i = 0; i < m_undoLimit; ++i) {
Chris@376 451 stack.push(tempStack.top());
Chris@376 452 tempStack.pop();
Chris@376 453 }
Chris@376 454 }
Chris@376 455 }
Chris@376 456
Chris@376 457 void
Chris@376 458 CommandHistory::clearStack(CommandStack &stack)
Chris@376 459 {
Chris@376 460 while (!stack.empty()) {
Chris@376 461 Command *command = stack.top();
Chris@376 462 // Not safe to call getName() on a command about to be deleted
Chris@377 463 #ifdef DEBUG_COMMAND_HISTORY
Chris@377 464 std::cerr << "CommandHistory::clearStack: About to delete command " << command << std::endl;
Chris@377 465 #endif
Chris@376 466 delete command;
Chris@376 467 stack.pop();
Chris@376 468 }
Chris@376 469 }
Chris@376 470
Chris@376 471 void
Chris@376 472 CommandHistory::undoActivated(QAction *action)
Chris@376 473 {
Chris@376 474 int pos = m_actionCounts[action];
Chris@376 475 for (int i = 0; i <= pos; ++i) {
Chris@376 476 undo();
Chris@376 477 }
Chris@376 478 }
Chris@376 479
Chris@376 480 void
Chris@376 481 CommandHistory::redoActivated(QAction *action)
Chris@376 482 {
Chris@376 483 int pos = m_actionCounts[action];
Chris@376 484 for (int i = 0; i <= pos; ++i) {
Chris@376 485 redo();
Chris@376 486 }
Chris@376 487 }
Chris@376 488
Chris@376 489 void
Chris@376 490 CommandHistory::updateActions()
Chris@376 491 {
Chris@376 492 m_actionCounts.clear();
Chris@376 493
Chris@376 494 for (int undo = 0; undo <= 1; ++undo) {
Chris@376 495
Chris@376 496 QAction *action(undo ? m_undoAction : m_redoAction);
Chris@376 497 QAction *menuAction(undo ? m_undoMenuAction : m_redoMenuAction);
Chris@376 498 QMenu *menu(undo ? m_undoMenu : m_redoMenu);
Chris@376 499 CommandStack &stack(undo ? m_undoStack : m_redoStack);
Chris@376 500
Chris@376 501 if (stack.empty()) {
Chris@376 502
Chris@376 503 QString text(undo ? tr("Nothing to undo") : tr("Nothing to redo"));
Chris@376 504
Chris@376 505 action->setEnabled(false);
Chris@376 506 action->setText(text);
Chris@376 507
Chris@376 508 menuAction->setEnabled(false);
Chris@376 509 menuAction->setText(text);
Chris@376 510
Chris@376 511 } else {
Chris@376 512
Chris@376 513 action->setEnabled(true);
Chris@376 514 menuAction->setEnabled(true);
Chris@376 515
Chris@376 516 QString commandName = stack.top()->getName();
Chris@376 517 commandName.replace(QRegExp("&"), "");
Chris@376 518
Chris@376 519 QString text = (undo ? tr("&Undo %1") : tr("Re&do %1"))
Chris@376 520 .arg(commandName);
Chris@376 521
Chris@376 522 action->setText(text);
Chris@376 523 menuAction->setText(text);
Chris@376 524 }
Chris@376 525
Chris@376 526 menu->clear();
Chris@376 527
Chris@376 528 CommandStack tempStack;
Chris@376 529 int j = 0;
Chris@376 530
Chris@376 531 while (j < m_menuLimit && !stack.empty()) {
Chris@376 532
Chris@376 533 Command *command = stack.top();
Chris@376 534 tempStack.push(command);
Chris@376 535 stack.pop();
Chris@376 536
Chris@376 537 QString commandName = command->getName();
Chris@376 538 commandName.replace(QRegExp("&"), "");
Chris@376 539
Chris@376 540 QString text;
Chris@376 541 if (undo) text = tr("&Undo %1").arg(commandName);
Chris@376 542 else text = tr("Re&do %1").arg(commandName);
Chris@376 543
Chris@376 544 QAction *action = menu->addAction(text);
Chris@376 545 m_actionCounts[action] = j++;
Chris@376 546 }
Chris@376 547
Chris@376 548 while (!tempStack.empty()) {
Chris@376 549 stack.push(tempStack.top());
Chris@376 550 tempStack.pop();
Chris@376 551 }
Chris@376 552 }
Chris@376 553 }
Chris@376 554