Scribus Developer Documentation - API
logo-pen

Scribus Developer Documentation - API

undomanager.cpp

Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 /***************************************************************************
00008  *   Copyright (C) 2005 by Riku Leino                                      *
00009  *   riku@scribus.info                                                     *
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  *   This program is distributed in the hope that it will be useful,       *
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00019  *   GNU General Public License for more details.                          *
00020  *                                                                         *
00021  *   You should have received a copy of the GNU General Public License     *
00022  *   along with this program; if not, write to the                         *
00023  *   Free Software Foundation, Inc.,                                       *
00024  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00025  ***************************************************************************/
00026 
00027 #include "undomanager.h"
00028 
00029 #include <QDebug>
00030 #include <QList>
00031 #include <QPixmap>
00032 
00033 #include "prefscontext.h"
00034 #include "prefsfile.h"
00035 #include "prefsmanager.h"
00036 #include "scconfig.h"
00037 #include "scpaths.h"
00038 #include "scraction.h"
00039 #include "scribuscore.h"
00040 #include "undogui.h"
00041 #include "undostack.h"
00042 #include "util_icon.h"
00043 
00044 
00045 /**************************************************************************************/
00046 
00051 struct TransactionData : public Transaction::TransactionStateBase
00052 {
00053     int stackLevel;
00054     UndoManager* UM;
00055     UndoObject* transactionObject;  // will be DummyUndoObject
00056     TransactionState* transactionState;
00057 };
00058 
00059 
00060 /**************************************************************************************/
00061 
00062 
00063 
00064 UndoManager* UndoManager::instance_          = 0;
00065 bool         UndoManager::undoEnabled_       = true;
00066 int          UndoManager::undoEnabledCounter_ = 0;
00067 
00068 UndoManager* UndoManager::instance()
00069 {
00070     if (instance_ == 0)
00071         instance_ = new UndoManager();
00072 
00073     return instance_;
00074 }
00075 
00076 void UndoManager::setUndoEnabled(bool isEnabled)
00077 {
00078     if (isEnabled && undoEnabledCounter_ == 0)
00079         return; // nothing to do undo is already enabled.
00080     else if (isEnabled && undoEnabledCounter_ > 0)
00081         --undoEnabledCounter_;
00082     else if (!isEnabled)
00083         ++undoEnabledCounter_;
00084 
00085     undoEnabled_ = undoEnabledCounter_ == 0;
00086     if (undoEnabled_)
00087         connectGuis();
00088     else if (undoEnabledCounter_ == 1)
00089         disconnectGuis(); // disconnect only once when setUndoEnabled(false) has been called
00090                           // no need to call again if next setUndoEnabled() call will also be false.
00091 }
00092 
00093 bool UndoManager::undoEnabled()
00094 {
00095     return undoEnabled_;
00096 }
00097 
00098 UndoManager::UndoManager()
00099 {
00100     currentUndoObjectId_ = -1;
00101     if (!UndoManager::IGuides)
00102         initIcons();
00103     prefs_ = PrefsManager::instance()->prefsFile->getContext("undo");
00104     languageChange();
00105     setUndoEnabled(prefs_->getBool("enabled", true));
00106 }
00107 
00108 
00109 
00110 UndoTransaction UndoManager::beginTransaction(const QString &targetName,
00111                                               QPixmap *targetPixmap,
00112                                               const QString &name,
00113                                               const QString &description,
00114                                               QPixmap *actionPixmap)
00115 {
00116     if (!undoEnabled_)
00117         return UndoTransaction(NULL);
00118     
00120     UndoObject* transactionTarget_ = new DummyUndoObject();
00121     TransactionState* transactionState_ = new TransactionState();
00122     transactionTarget_->setUName(targetName); // Name which will be in action history
00123     if (targetPixmap)
00124         transactionTarget_->setUPixmap(targetPixmap);
00125     if (name.length() > 0)          // if left to 0 length action will be fetched from the
00126         transactionState_->setName(name); // last added UndoState in this transaction
00127     if (description.length() > 0)
00128         transactionState_->setDescription(description); // tool tip for action history
00129     if (actionPixmap)
00130         transactionState_->setPixmap(actionPixmap); // for action history
00131 
00132     // Holds the state and data of this transaction:
00133     TransactionData *transaction = new TransactionData();
00134     transaction->transactionObject = transactionTarget_;
00135     transaction->transactionState = transactionState_;
00136     transaction->stackLevel = transactions_.size();
00137     transaction->UM = this;
00138     
00139     transactions_.push_back(transaction);
00140     
00141 //  qDebug() << "UndoManager::beginTransaction" << targetName << name << transaction;
00142     return UndoTransaction(transaction);
00143 }
00144 
00145 UndoTransaction::UndoTransaction(TransactionData* data) : Transaction(data) 
00146 {};
00147 
00148 UndoTransaction::~UndoTransaction() 
00149 {
00150     if (m_data)
00151     {
00152         UndoTransaction::cancel(); // no virtual calls in destructor
00153         delete m_data; 
00154         m_data = 0;
00155     }
00156 }
00157 
00158 bool UndoTransaction::cancel()
00159 {
00160     if (!m_data)
00161         return false;
00162     
00163     TransactionData* data = static_cast<TransactionData*>(m_data);
00164     UndoManager* UM = data->UM;
00165     int stackLevel = data->stackLevel;
00166 
00167     switch (m_data->m_status)
00168     {
00169         case Transaction::STATE_OPEN:
00170         case Transaction::STATE_WILLFAIL:
00171 //          qDebug() << "UndoManager::cancelTransaction" << data << data->transactionObject->getUName() << data->transactionState->getName() << stackLevel;
00172             data->m_status = Transaction::STATE_FAILED;
00173             delete data->transactionObject;
00174             data->transactionObject = 0;
00175             delete data->transactionState;
00176             data->transactionState = 0;
00177             //brutal for now:
00178             assert (stackLevel + 1 == signed(UM->transactions_.size()));
00179             if (stackLevel < signed(UM->transactions_.size()))
00180             {
00181                 UM->transactions_.erase(UM->transactions_.begin() + stackLevel);
00182             }
00183             return true;
00184         default:
00185             // do nothing;
00186 //          qDebug() << "UndoManager::cancelTransaction ** already closed **";
00187             return false;
00188     }
00189 }
00190 
00191 bool UndoTransaction::commit(const QString &targetName,
00192                              QPixmap *targetPixmap,
00193                              const QString &name,
00194                              const QString &description,
00195                              QPixmap *actionPixmap)
00196 {
00197     if (m_data && m_data->m_status == Transaction::STATE_OPEN)
00198     {
00199         TransactionData* data = static_cast<TransactionData*>(m_data);
00200         if (targetName.length() > 0)
00201             data->transactionObject->setUName(targetName);
00202         if (targetPixmap)
00203             data->transactionObject->setUPixmap(targetPixmap);
00204         if (name.length() > 0)
00205             data->transactionState->setName(name);
00206         if (description.length() > 0)
00207             data->transactionState->setDescription(description);
00208         if (actionPixmap)
00209             data->transactionState->setPixmap(actionPixmap);
00210     }
00211     return commit();
00212 }
00213                 
00214     
00215 bool UndoTransaction::commit()
00216 {
00217     if (!m_data)
00218         return false;
00219     TransactionData* data = static_cast<TransactionData*>(m_data);
00220     UndoManager* UM = data->UM;
00221     int stackLevel = data->stackLevel;
00222 
00223     if (!UM->undoEnabled_)
00224     {
00225         cancel();
00226         return false;
00227     }
00228     
00229     UndoObject *tmpu = UM->transactions_.at(stackLevel)->transactionObject;
00230     TransactionState *tmps = UM->transactions_.at(stackLevel)->transactionState;
00231     
00232     switch (m_data->m_status)
00233     {
00234         case Transaction::STATE_OPEN:
00235 //          qDebug() << "UndoManager::commitTransaction" << data << data->transactionObject->getUName() << data->transactionState->getName() << stackLevel;
00236             m_data->m_status = Transaction::STATE_COMMITTED;
00237 
00238             // brutal for now:
00239             assert (stackLevel + 1 == signed(UM->transactions_.size()));
00240             
00241             if (stackLevel < signed(UM->transactions_.size()))
00242             {
00243                 UM->transactions_.erase(UM->transactions_.begin() + stackLevel);
00244             }
00245                 
00246             if (tmps->sizet() > 0) // are there any actions inside the commited transaction
00247             {
00248                 if (tmps->getName().isEmpty())
00249                     tmps->useActionName();
00250                 UM->action(tmpu, tmps);
00251             } // if not just delete objects
00252             else
00253             {
00254                 delete tmpu;
00255                 tmpu = 0;
00256                 delete tmps;
00257                 tmps = 0;
00258             }
00259             return true;
00260             break;
00261         case STATE_WILLFAIL:
00262             return cancel();
00263             break;
00264         default:
00265 //          qDebug() << "UndoManager::commitTransaction ** already closed **";
00266             // nothing
00267             break;
00268     }
00269     return false;
00270 }
00271 
00272 bool UndoManager::isTransactionMode()
00273 {
00274     return transactions_.size() > 0;
00275 }
00276 
00277 void UndoManager::registerGui(UndoGui* gui)
00278 {
00279     if (gui == 0)
00280         return;
00281 
00282     setUndoEnabled(false);
00283     setState(gui);
00284     undoGuis_.push_back(gui);
00285     setUndoEnabled(true);
00286 }
00287 
00288 void UndoManager::setState(UndoGui* gui, int uid)
00289 {
00290     gui->clear();
00291 
00292     if ( stacks_[currentDoc_].size() == 0 )
00293         return;
00294 
00295     StateList::iterator itstartU = stacks_[currentDoc_].undoActions_.begin(); // undo actions
00296     StateList::iterator itendU   = stacks_[currentDoc_].undoActions_.end();
00297 
00298     StateList::iterator itstartR = stacks_[currentDoc_].redoActions_.begin(); // redo actions
00299     StateList::iterator itendR   = stacks_[currentDoc_].redoActions_.end();
00300 
00301     if (uid > -1)
00302     { // find the range from where actions are added when in obj. spec. mode
00303         StateList::iterator it2;
00304         for (it2 = stacks_[currentDoc_].undoActions_.begin();
00305              it2 != stacks_[currentDoc_].undoActions_.end(); ++it2)
00306         {
00307             UndoState*  tmp  = *it2;
00308             TransactionState *ts = dynamic_cast<TransactionState*>(tmp);
00309             if (ts && !ts->containsOnly(uid))
00310             {
00311                 if (it2 != stacks_[currentDoc_].undoActions_.begin())
00312                     itendU = --it2;
00313                 break;
00314             }
00315         }
00316         StateList::iterator it3;
00317         for (it3 = stacks_[currentDoc_].redoActions_.begin();
00318              it3 != stacks_[currentDoc_].redoActions_.end(); ++it3)
00319         {
00320             UndoState*  tmp  = *it3;
00321             TransactionState *ts = dynamic_cast<TransactionState*>(tmp);
00322             if (ts && !ts->containsOnly(uid))
00323             {
00324                 itendR = it3;
00325                 break;
00326             }
00327         }
00328     }
00329 
00330     if (stacks_[currentDoc_].undoItems() > 0)
00331     {
00332         if (itendU == stacks_[currentDoc_].undoActions_.end())
00333             --itendU;
00334         for (; itendU >= itstartU; --itendU) // insert undo actions
00335         {
00336             UndoState*  state  = *itendU;
00337             UndoObject* target = state->undoObject();
00338 
00339             if (target && (uid == -1 || target->getUId() == static_cast<uint>(uid)))
00340                 gui->insertUndoItem(target, state);
00341             if (itendU == itstartU)
00342                 break;
00343         }
00344     }
00345 
00346     if (stacks_[currentDoc_].redoItems() > 0)
00347     {
00348         --itendR;
00349         for (; itstartR <= itendR; ++itstartR) // insert redo actions
00350         {
00351             UndoState*  state  = *itstartR;
00352             UndoObject* target = state->undoObject();
00353 
00354             if (target && (uid == -1 || target->getUId() == static_cast<uint>(uid)))
00355                 gui->insertRedoItem(target, state);
00356             if (itendR == itstartR)
00357                 break;
00358         }
00359     }
00360 }
00361 
00362 void UndoManager::connectGuis()
00363 {
00364     for (uint i = 0; i < undoGuis_.size(); ++i)
00365     {
00366         UndoGui *gui = undoGuis_[i];
00367 
00368         connect(gui, SIGNAL(undo(int)), this, SLOT(undo(int)));
00369         connect(gui, SIGNAL(redo(int)), this, SLOT(redo(int)));
00370         connect(this, SIGNAL(newAction(UndoObject*, UndoState*)),
00371                 gui, SLOT(insertUndoItem(UndoObject*, UndoState*)));
00372         connect(this, SIGNAL(popBack()), gui, SLOT(popBack()));
00373         connect(this, SIGNAL(undoSignal(int)), gui, SLOT(updateUndo(int)));
00374         connect(this, SIGNAL(redoSignal(int)), gui, SLOT(updateRedo(int)));
00375         connect(this, SIGNAL(clearRedo()), gui, SLOT(clearRedo()));
00376         gui->setEnabled(true);
00377         gui->updateUndoActions();
00378     }
00379 }
00380 
00381 void UndoManager::disconnectGuis()
00382 {
00383     for (uint i = 0; i < undoGuis_.size(); ++i)
00384     {
00385         UndoGui *gui = undoGuis_[i];
00386 
00387         disconnect(gui, SIGNAL(undo(int)), this, SLOT(undo(int)));
00388         disconnect(gui, SIGNAL(redo(int)), this, SLOT(redo(int)));
00389         disconnect(this, SIGNAL(newAction(UndoObject*, UndoState*)),
00390                    gui, SLOT(insertUndoItem(UndoObject*, UndoState*)));
00391         disconnect(this, SIGNAL(popBack()), gui, SLOT(popBack()));
00392         disconnect(this, SIGNAL(undoSignal(int)), gui, SLOT(updateUndo(int)));
00393         disconnect(this, SIGNAL(redoSignal(int)), gui, SLOT(updateRedo(int)));
00394         disconnect(this, SIGNAL(clearRedo()), gui, SLOT(clearRedo()));
00395         gui->setEnabled(false);
00396     }
00397 }
00398 
00399 void UndoManager::removeGui(UndoGui* gui)
00400 {
00401     std::vector<UndoGui*>::iterator it = undoGuis_.begin();
00402     while(it != undoGuis_.end())
00403     {
00404         if (*it == gui)
00405             it = undoGuis_.erase(it);
00406         else  
00407             ++it;
00408     }
00409 }
00410 
00411 
00412 void UndoManager::switchStack(const QString& stackName)
00413 {
00414     if (stackName == currentDoc_)
00415         return; // already current stack
00416     currentDoc_ = stackName;
00417     if (!stacks_.contains(currentDoc_))
00418         stacks_[currentDoc_] = UndoStack();
00419 
00420     stacks_[currentDoc_].setMaxSize(prefs_->getInt("historylength", 20));
00421     for (uint i = 0; i < undoGuis_.size(); ++i)
00422         setState(undoGuis_[i]);
00423 
00424     setTexts();
00425 }
00426 
00427 void UndoManager::renameStack(const QString& newName)
00428 {
00429     if (currentDoc_ == newName)
00430         return;
00431 
00432     if (stacks_[currentDoc_].size() == 0) {
00433         currentDoc_ = newName;
00434         return;
00435     }
00436     
00437     UndoStack tmp(stacks_[currentDoc_]);
00438     stacks_.remove(currentDoc_);
00439     stacks_[newName] = tmp;
00440     currentDoc_ = newName;
00441 }
00442 
00443 void UndoManager::removeStack(const QString& stackName)
00444 {
00445     if (stacks_.contains(stackName))
00446     {
00447         stacks_[stackName].clear();
00448         stacks_.remove(stackName);
00449         if (currentDoc_ == stackName)
00450         {
00451             for (uint i = 0; i < undoGuis_.size(); ++i)
00452                 undoGuis_[i]->clear();
00453             currentDoc_ = "__no_name__";
00454         }
00455     }
00456 }
00457 
00458 void UndoManager::clearStack()
00459 {
00460     stacks_[currentDoc_].clear();
00461     for (uint i = 0; i < undoGuis_.size(); ++i)
00462     {
00463         undoGuis_[i]->clear();
00464         setState(undoGuis_[i]);
00465     }
00466 }
00467 
00468 void UndoManager::action(UndoObject* target, UndoState* state, QPixmap *targetPixmap)
00469 {
00470     QPixmap *oldIcon = 0;
00471     if (targetPixmap)
00472     {
00473         oldIcon = target->getUPixmap();
00474         target->setUPixmap(targetPixmap);
00475     }
00476 
00477     if (!undoEnabled_) // if so flush down the state
00478     {
00479         TransactionState *ts = dynamic_cast<TransactionState*>(state);
00480         if (ts) // flush the TransactionObject too
00481             delete target;
00482         delete state;
00483         return;
00484     }
00485 
00486     if (!isTransactionMode() &&
00487         (currentUndoObjectId_ == -1 || currentUndoObjectId_ == static_cast<long>(target->getUId())))
00488     {
00489 //      qDebug() << "UndoManager: new Action" << state->getName() << "for" << currentUndoObjectId_;
00490         emit newAction(target, state); // send action to the guis
00491     }
00492     else
00493     {
00494         emit clearRedo();
00495     }
00496     if (isTransactionMode())
00497     {
00498 //      qDebug() << "UndoManager: Action stored for transaction:" << transactions_.back() << target->getUName() << state->getName();
00499         transactions_.back()->transactionState->pushBack(target, state);
00500     }
00501     else
00502     {
00503 //      qDebug() << "UndoManager: Action executed:" << target->getUName() << state->getName();
00504         state->setUndoObject(target);
00505         stacks_[currentDoc_].action(state);
00506     }
00507     if (targetPixmap)
00508         target->setUPixmap(oldIcon);
00509 
00510     setTexts();
00511 }
00512 
00513 void UndoManager::action(UndoObject* target, UndoState* state,
00514                          const QString &targetName, QPixmap *targetPixmap)
00515 {
00516     QString oldName = target->getUName();
00517     if (!targetName.isEmpty())
00518         target->setUName(targetName);
00519     action(target, state, targetPixmap);
00520     target->setUName(oldName);
00521 }
00522 
00523 void UndoManager::undo(int steps)
00524 {
00525     if (!undoEnabled_)
00526         return;
00527 
00528     setUndoEnabled(false);
00529     stacks_[currentDoc_].undo(steps, currentUndoObjectId_);
00530     setUndoEnabled(true);
00531     emit undoSignal(steps);
00532     emit undoRedoDone();
00533     setTexts();
00534 }
00535 
00536 void UndoManager::redo(int steps)
00537 {
00538     if (!undoEnabled_)
00539         return;
00540 
00541     setUndoEnabled(false);
00542     stacks_[currentDoc_].redo(steps, currentUndoObjectId_);
00543     setUndoEnabled(true);
00544     emit redoSignal(steps);
00545     emit undoRedoDone();
00546     setTexts();
00547 }
00548 
00549 bool UndoManager::hasUndoActions(int )
00550 {
00551     // TODO Needs to fixed for object specific mode
00552     return stacks_[currentDoc_].undoItems() > 0;
00553 }
00554 
00555 bool UndoManager::hasRedoActions(int )
00556 {
00557     // TODO Needs to be fixed for object specific mode
00558     return stacks_[currentDoc_].redoItems() > 0;
00559 }
00560 
00561 void UndoManager::showObject(int uid)
00562 {
00563     if (currentUndoObjectId_ == uid)
00564         return;
00565     setUndoEnabled(false);
00566     currentUndoObjectId_ = uid;
00567     for (uint i = 0; i < undoGuis_.size(); ++i)
00568     {
00569         if (uid == -2)
00570             undoGuis_[i]->clear();
00571         else
00572             setState(undoGuis_[i], currentUndoObjectId_);
00573     }
00574     setUndoEnabled(true);
00575     setTexts();
00576 }
00577 
00578 UndoObject* UndoManager::replaceObject(ulong uid, UndoObject *newUndoObject)
00579 {
00580     UndoObject *tmp = 0;
00581     TransactionState* transaction_ = NULL;
00582     if (transactions_.size() > 0)
00583         transaction_ = transactions_.at(transactions_.size()-1)->transactionState;
00584     for (uint i = 0; i < stacks_[currentDoc_].undoActions_.size(); ++i)
00585     {
00586         UndoState *tmpState = stacks_[currentDoc_].undoActions_[i];
00587         TransactionState *ts = dynamic_cast<TransactionState*>(tmpState);
00588         if (ts)
00589             tmp = ts->replace(uid, newUndoObject);
00590         else if (tmpState->undoObject() && tmpState->undoObject()->getUId() == uid)
00591         {
00592             tmp = tmpState->undoObject();
00593             tmpState->setUndoObject(newUndoObject);
00594         }
00595     }
00596     if (transaction_) // replace also in the currently open transaction
00597         tmp = transaction_->replace(uid, newUndoObject);
00598     return tmp;
00599 }
00600 
00601 void UndoManager::setHistoryLength(int steps)
00602 {
00603     if (steps >= 0)
00604     {
00605         stacks_[currentDoc_].setMaxSize(static_cast<uint>(steps));
00606         prefs_->set("historylength", stacks_[currentDoc_].maxSize());
00607     }
00608 }
00609 
00610 void UndoManager::setAllHistoryLengths(int steps)
00611 {
00612     if (steps >= 0)
00613     {
00614         for (StackMap::Iterator it = stacks_.begin(); it != stacks_.end(); ++it )
00615         {
00616             it.value().setMaxSize(static_cast<uint>(steps));
00617         }
00618         prefs_->set("historylength", steps);
00619     }
00620 }
00621 
00622 int UndoManager::getHistoryLength()
00623 {
00624     if (stacks_.size() > 0 && stacks_[currentDoc_].redoItems() > 0)
00625         return -1;
00626     return static_cast<int>(stacks_[currentDoc_].maxSize());
00627 }
00628 
00629 bool UndoManager::isGlobalMode()
00630 {
00631     return currentUndoObjectId_ == -1;
00632 }
00633 
00634 void UndoManager::setTexts()
00635 {
00636     if (stacks_[currentDoc_].undoItems() > 0)
00637     {
00638         UndoState *state = stacks_[currentDoc_].getNextUndo(currentUndoObjectId_);
00639         if (state)
00640             ScCore->primaryMainWindow()->scrActions["editUndoAction"]->setTexts(QString(Um::MenuUndo).arg(state->getName()));
00641         else
00642             ScCore->primaryMainWindow()->scrActions["editUndoAction"]->setTexts(Um::MenuUndoEmpty);
00643     }
00644     else
00645         ScCore->primaryMainWindow()->scrActions["editUndoAction"]->setTexts(Um::MenuUndoEmpty);
00646 
00647     if (stacks_[currentDoc_].redoItems() > 0)
00648     {
00649         UndoState *state = stacks_[currentDoc_].getNextRedo(currentUndoObjectId_);
00650         if (state)
00651             ScCore->primaryMainWindow()->scrActions["editRedoAction"]->setTexts(QString(Um::MenuRedo).arg(state->getName()));
00652         else
00653             ScCore->primaryMainWindow()->scrActions["editRedoAction"]->setTexts(Um::MenuRedoEmpty);
00654     }
00655     else
00656         ScCore->primaryMainWindow()->scrActions["editRedoAction"]->setTexts(Um::MenuRedoEmpty);
00657 }
00658 
00659 void UndoManager::deleteInstance()
00660 {
00661     if (instance_)
00662         delete instance_;
00663     instance_ = 0;
00664 }
00665 
00666 UndoManager::~UndoManager()
00667 {
00668     StackMap::iterator it;
00669     for (it = stacks_.begin(); it != stacks_.end(); ++it)
00670     {
00671         for (uint i = 0; i < (*it).size(); ++i)
00672         {
00673             (*it).clear();
00674         }
00675     }
00676     stacks_.clear();
00677 }
00678 
00679 /*** TransactionState *****************************************************/
00680 
00681 TransactionState::TransactionState() : UndoState("")
00682 {
00683     size_ = 0;
00684 }
00685 
00686 UndoState* TransactionState::at(int index)
00687 {
00688     if (index >= 0 && static_cast<uint>(index) < sizet())
00689         return states_[index];
00690     else
00691         return 0;
00692 }
00693 
00694 bool TransactionState::contains(int uid) const
00695 {
00696     for (uint i = 0; i < states_.size(); ++i)
00697     {
00698         if (states_[i]->undoObject()->getUId() == static_cast<uint>(uid))
00699             return true;
00700     }
00701     return false;
00702 }
00703 
00704 bool TransactionState::containsOnly(int uid) const
00705 {
00706     for (uint i = 0; i < states_.size(); ++i)
00707     {
00708         if (states_[i]->undoObject()->getUId() != static_cast<uint>(uid))
00709             return false;
00710     }
00711     return true;
00712 }
00713 
00714 void TransactionState::pushBack(UndoObject *target, UndoState *state)
00715 {
00716     if (target && state)
00717     {
00718         state->setUndoObject(target);
00719         states_.push_back(state);
00720         ++size_;
00721     }
00722 }
00723 
00724 uint TransactionState::sizet()
00725 {
00726     return size_;
00727 }
00728 
00729 void TransactionState::useActionName()
00730 {
00731     if (size_ > 0)
00732         setName(states_[size_ - 1]->getName());
00733 }
00734 
00735 UndoObject* TransactionState::replace(ulong uid, UndoObject *newUndoObject)
00736 {
00737     UndoObject *tmp = 0;
00738     for (uint i = 0; i < states_.size(); ++i)
00739     {
00740         TransactionState *ts = dynamic_cast<TransactionState*>(states_[i]);
00741         if (ts) // are we having a transaction_inside a transaction
00742             ts->replace(uid, newUndoObject);
00743         else if (states_[i]->undoObject() && states_[i]->undoObject()->getUId() == uid)
00744         {
00745             tmp = states_[i]->undoObject();
00746             states_[i]->setUndoObject(newUndoObject);
00747         }
00748     }
00749     return tmp;
00750 }
00751 
00752 void TransactionState::undo() // undo all attached states
00753 {
00754     for (int i = sizet() - 1; i > -1; --i)
00755         at(i)->undo();
00756 }
00757 
00758 void TransactionState::redo() // redo all attached states
00759 {
00760     for (uint i = 0; i < sizet(); ++i)
00761         at(i)->redo();
00762 }
00763 
00764 TransactionState::~TransactionState()
00765 {
00766     for (uint i = 0; i < states_.size(); ++i)
00767     {
00768         if (states_[i])
00769         {
00770             delete states_[i];
00771             states_[i] = 0;
00772         }
00773     }
00774 }
00775 
00776 /*************************************************************************************/
00777 
00778 void UndoManager::languageChange()
00779 {
00780     UndoManager::AddVGuide          = tr("Add vertical guide");
00781     UndoManager::AddHGuide          = tr("Add horizontal guide");
00782     UndoManager::DelVGuide          = tr("Remove vertical guide");
00783     UndoManager::DelHGuide          = tr("Remove horizontal guide");
00784     UndoManager::DelVAGuide         = tr("Remove vertical auto guide");
00785     UndoManager::DelHAGuide         = tr("Remove horizontal auto guide");
00786     UndoManager::MoveVGuide         = tr("Move vertical guide");
00787     UndoManager::MoveHGuide         = tr("Move horizontal guide");
00788     UndoManager::LockGuides         = tr("Lock guides");
00789     UndoManager::UnlockGuides       = tr("Unlock guides");
00790     UndoManager::Move               =