diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 3f33b882e8..c6f388b511 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -849,145 +849,6 @@ void Application::setActiveDocument(const char *Name) } } -AutoTransaction::AutoTransaction(const char *name, bool tmpName) { - auto &app = GetApplication(); - if(name && app._activeTransactionGuard>=0) { - if(!app.getActiveTransaction() - || (!tmpName && app._activeTransactionTmpName)) - { - FC_LOG("auto transaction '" << name << "', " << tmpName); - tid = app.setActiveTransaction(name); - app._activeTransactionTmpName = tmpName; - } - } - // We use negative transaction guard to disable auto transaction from here - // and any stack below. This is to support user setting active transaction - // before having any existing AutoTransaction on stack, or 'persist' - // transaction that can out live AutoTransaction. - if(app._activeTransactionGuard<0) - --app._activeTransactionGuard; - else if(tid || app._activeTransactionGuard>0) - ++app._activeTransactionGuard; - else if(app.getActiveTransaction()) { - FC_LOG("auto transaction disabled because of '" << app._activeTransactionName << "'"); - --app._activeTransactionGuard; - } else - ++app._activeTransactionGuard; - FC_TRACE("construct auto Transaction " << app._activeTransactionGuard); -} - -AutoTransaction::~AutoTransaction() { - auto &app = GetApplication(); - FC_TRACE("before destruct auto Transaction " << app._activeTransactionGuard); - if(app._activeTransactionGuard<0) - ++app._activeTransactionGuard; - else if(!app._activeTransactionGuard) { -#ifdef FC_DEBUG - FC_ERR("Transaction guard error"); -#endif - } else if(--app._activeTransactionGuard == 0) { - try { - // We don't call close() here, because close() only closes - // transaction that we opened during construction time. However, - // when _activeTransactionGuard reaches zero here, we are supposed - // to close any transaction opened. - app.closeActiveTransaction(); - } catch(Base::Exception &e) { - e.ReportException(); - } catch(...) - {} - } - FC_TRACE("destruct auto Transaction " << app._activeTransactionGuard); -} - -void AutoTransaction::close(bool abort) { - if(tid || abort) { - GetApplication().closeActiveTransaction(abort,abort?0:tid); - tid = 0; - } -} - -void AutoTransaction::setEnable(bool enable) { - auto &app = GetApplication(); - if(!app._activeTransactionGuard) - return; - if((enable && app._activeTransactionGuard>0) - || (!enable && app._activeTransactionGuard<0)) - return; - app._activeTransactionGuard = -app._activeTransactionGuard; - FC_TRACE("toggle auto Transaction " << app._activeTransactionGuard); - if(!enable && app._activeTransactionTmpName) { - bool close = true; - for(auto &v : app.DocMap) { - if(v.second->hasPendingTransaction()) { - close = false; - break; - } - } - if(close) - app.closeActiveTransaction(); - } -} - -int Application::setActiveTransaction(const char *name, bool persist) { - if(!name || !name[0]) - name = "Command"; - - if(_activeTransactionGuard>0 && getActiveTransaction()) { - if(_activeTransactionTmpName) { - FC_LOG("transaction rename to '" << name << "'"); - for(auto &v : DocMap) - v.second->renameTransaction(name,_activeTransactionID); - } else { - if(persist) - AutoTransaction::setEnable(false); - return 0; - } - }else{ - FC_LOG("set active transaction '" << name << "'"); - _activeTransactionID = 0; - for(auto &v : DocMap) - v.second->_commitTransaction(); - _activeTransactionID = Transaction::getNewID(); - } - _activeTransactionTmpName = false; - _activeTransactionName = name; - if(persist) - AutoTransaction::setEnable(false); - return _activeTransactionID; -} - -const char *Application::getActiveTransaction(int *id) const { - int tid = 0; - if(Transaction::getLastID() == _activeTransactionID) - tid = _activeTransactionID; - if(id) *id = tid; - return tid?_activeTransactionName.c_str():0; -} - -void Application::closeActiveTransaction(bool abort, int id) { - if(!id) id = _activeTransactionID; - if(!id) return; - - if(_activeTransactionGuard>0 && !abort) { - FC_LOG("ignore close transaction"); - return; - } - - FC_LOG("close transaction '" << _activeTransactionName << "' " << abort); - _activeTransactionID = 0; - - TransactionSignaller siganller(abort,false); - for(auto &v : DocMap) { - if(v.second->getTransactionID(true) != id) - continue; - if(abort) - v.second->_abortTransaction(); - else - v.second->_commitTransaction(); - } -} - static int _TransSignalCount; static bool _TransSignalled; Application::TransactionSignaller::TransactionSignaller(bool abort, bool signal) diff --git a/src/App/Application.h b/src/App/Application.h index 35bc7d264c..2a2f0aca83 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -568,60 +568,6 @@ inline App::Application &GetApplication(void){ return *App::Application::_pcSingleton; } -/// Helper class to manager transaction (i.e. undo/redo) -class AppExport AutoTransaction { -private: - /// Private new operator to prevent heap allocation - void* operator new(size_t size); - -public: - /** Constructor - * - * @param name: optional new transaction name on construction - * @param tmpName: if true and a new transaction is setup, the name given is - * considered as temporary, and subsequent construction of this class (or - * calling Application::setActiveTransaction()) can override the transaction - * name. - * - * The constructor increments an internal counter - * (Application::_activeTransactionGuard). The counter prevents any new - * active transaction being setup. It also prevents close (i.e. commits) the - * current active transaction until it reaches zero. It does not have any - * effect on aborting transaction, though. - */ - AutoTransaction(const char *name=0, bool tmpName=false); - - /** Destructor - * - * This destructor decrease an internal counter - * (Application::_activeTransactionGuard), and will commit any current - * active transaction when the counter reaches zero. - */ - ~AutoTransaction(); - - /** Close or abort the transaction - * - * This function can be used to explicitly close (i.e. commit) the - * transaction, if the current transaction ID matches the one created inside - * the constructor. For aborting, it will abort any current transaction - */ - void close(bool abort=false); - - /** Enable/Disable any AutoTransaction instance in the current stack - * - * Once disabled, any empty temporary named transaction is closed. If there - * are non-empty or non-temperary named active transaction, it will not be - * auto closed. - * - * This function may be used in, for example, Gui::Document::setEdit() to - * allow a transaction live past any command scope. - */ - static void setEnable(bool enable); - -private: - int tid = 0; -}; - } // namespace App diff --git a/src/App/AutoTransaction.cpp b/src/App/AutoTransaction.cpp new file mode 100644 index 0000000000..d6fe5e7c51 --- /dev/null +++ b/src/App/AutoTransaction.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** + * Copyright (c) 2019 Zheng, Lei (realthunder) * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ****************************************************************************/ + +#include "PreCompiled.h" +#include +#include "Application.h" +#include "Transactions.h" +#include "Document.h" +#include "AutoTransaction.h" + +FC_LOG_LEVEL_INIT("App",true,true); + +using namespace App; + +AutoTransaction::AutoTransaction(const char *name, bool tmpName) { + auto &app = GetApplication(); + if(name && app._activeTransactionGuard>=0) { + if(!app.getActiveTransaction() + || (!tmpName && app._activeTransactionTmpName)) + { + FC_LOG("auto transaction '" << name << "', " << tmpName); + tid = app.setActiveTransaction(name); + app._activeTransactionTmpName = tmpName; + } + } + // We use negative transaction guard to disable auto transaction from here + // and any stack below. This is to support user setting active transaction + // before having any existing AutoTransaction on stack, or 'persist' + // transaction that can out live AutoTransaction. + if(app._activeTransactionGuard<0) + --app._activeTransactionGuard; + else if(tid || app._activeTransactionGuard>0) + ++app._activeTransactionGuard; + else if(app.getActiveTransaction()) { + FC_LOG("auto transaction disabled because of '" << app._activeTransactionName << "'"); + --app._activeTransactionGuard; + } else + ++app._activeTransactionGuard; + FC_TRACE("construct auto Transaction " << app._activeTransactionGuard); +} + +AutoTransaction::~AutoTransaction() { + auto &app = GetApplication(); + FC_TRACE("before destruct auto Transaction " << app._activeTransactionGuard); + if(app._activeTransactionGuard<0) + ++app._activeTransactionGuard; + else if(!app._activeTransactionGuard) { +#ifdef FC_DEBUG + FC_ERR("Transaction guard error"); +#endif + } else if(--app._activeTransactionGuard == 0) { + try { + // We don't call close() here, because close() only closes + // transaction that we opened during construction time. However, + // when _activeTransactionGuard reaches zero here, we are supposed + // to close any transaction opened. + app.closeActiveTransaction(); + } catch(Base::Exception &e) { + e.ReportException(); + } catch(...) + {} + } + FC_TRACE("destruct auto Transaction " << app._activeTransactionGuard); +} + +void AutoTransaction::close(bool abort) { + if(tid || abort) { + GetApplication().closeActiveTransaction(abort,abort?0:tid); + tid = 0; + } +} + +void AutoTransaction::setEnable(bool enable) { + auto &app = GetApplication(); + if(!app._activeTransactionGuard) + return; + if((enable && app._activeTransactionGuard>0) + || (!enable && app._activeTransactionGuard<0)) + return; + app._activeTransactionGuard = -app._activeTransactionGuard; + FC_TRACE("toggle auto Transaction " << app._activeTransactionGuard); + if(!enable && app._activeTransactionTmpName) { + bool close = true; + for(auto &v : app.DocMap) { + if(v.second->hasPendingTransaction()) { + close = false; + break; + } + } + if(close) + app.closeActiveTransaction(); + } +} + +int Application::setActiveTransaction(const char *name, bool persist) { + if(!name || !name[0]) + name = "Command"; + + if(_activeTransactionGuard>0 && getActiveTransaction()) { + if(_activeTransactionTmpName) { + FC_LOG("transaction rename to '" << name << "'"); + for(auto &v : DocMap) + v.second->renameTransaction(name,_activeTransactionID); + } else { + if(persist) + AutoTransaction::setEnable(false); + return 0; + } + }else{ + FC_LOG("set active transaction '" << name << "'"); + _activeTransactionID = 0; + for(auto &v : DocMap) + v.second->_commitTransaction(); + _activeTransactionID = Transaction::getNewID(); + } + _activeTransactionTmpName = false; + _activeTransactionName = name; + if(persist) + AutoTransaction::setEnable(false); + return _activeTransactionID; +} + +const char *Application::getActiveTransaction(int *id) const { + int tid = 0; + if(Transaction::getLastID() == _activeTransactionID) + tid = _activeTransactionID; + if(id) *id = tid; + return tid?_activeTransactionName.c_str():0; +} + +void Application::closeActiveTransaction(bool abort, int id) { + if(!id) id = _activeTransactionID; + if(!id) return; + + if(_activeTransactionGuard>0 && !abort) { + FC_LOG("ignore close transaction"); + return; + } + + FC_LOG("close transaction '" << _activeTransactionName << "' " << abort); + _activeTransactionID = 0; + + TransactionSignaller siganller(abort,false); + for(auto &v : DocMap) { + if(v.second->getTransactionID(true) != id) + continue; + if(abort) + v.second->_abortTransaction(); + else + v.second->_commitTransaction(); + } +} + diff --git a/src/App/AutoTransaction.h b/src/App/AutoTransaction.h new file mode 100644 index 0000000000..f22fc123a4 --- /dev/null +++ b/src/App/AutoTransaction.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * Copyright (c) 2019 Zheng, Lei (realthunder) * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ****************************************************************************/ + +#ifndef APP_AUTOTRANSACTION_H +#define APP_AUTOTRANSACTION_H + +namespace App { + +/// Helper class to manager transaction (i.e. undo/redo) +class AppExport AutoTransaction { +private: + /// Private new operator to prevent heap allocation + void* operator new(size_t size); + +public: + /** Constructor + * + * @param name: optional new transaction name on construction + * @param tmpName: if true and a new transaction is setup, the name given is + * considered as temporary, and subsequent construction of this class (or + * calling Application::setActiveTransaction()) can override the transaction + * name. + * + * The constructor increments an internal counter + * (Application::_activeTransactionGuard). The counter prevents any new + * active transaction being setup. It also prevents close (i.e. commits) the + * current active transaction until it reaches zero. It does not have any + * effect on aborting transaction, though. + */ + AutoTransaction(const char *name=0, bool tmpName=false); + + /** Destructor + * + * This destructor decrease an internal counter + * (Application::_activeTransactionGuard), and will commit any current + * active transaction when the counter reaches zero. + */ + ~AutoTransaction(); + + /** Close or abort the transaction + * + * This function can be used to explicitly close (i.e. commit) the + * transaction, if the current transaction ID matches the one created inside + * the constructor. For aborting, it will abort any current transaction + */ + void close(bool abort=false); + + /** Enable/Disable any AutoTransaction instance in the current stack + * + * Once disabled, any empty temporary named transaction is closed. If there + * are non-empty or non-temporary named active transaction, it will not be + * auto closed. + * + * This function may be used in, for example, Gui::Document::setEdit() to + * allow a transaction live past any command scope. + */ + static void setEnable(bool enable); + +private: + int tid = 0; +}; + +} // namespace App + +#endif // APP_AUTOTRANSACTION_H diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt index 5dd583abb7..9ed3a7c1e5 100644 --- a/src/App/CMakeLists.txt +++ b/src/App/CMakeLists.txt @@ -254,6 +254,7 @@ SET(FreeCADApp_CPP_SRCS ${Properties_CPP_SRCS} Application.cpp ApplicationPy.cpp + AutoTransaction.cpp Branding.cpp ColorModel.cpp ComplexGeoData.cpp @@ -267,6 +268,7 @@ SET(FreeCADApp_HPP_SRCS ${Document_HPP_SRCS} ${Properties_HPP_SRCS} Application.h + AutoTransaction.h Branding.h ColorModel.h ComplexGeoData.h diff --git a/src/Gui/Command.cpp b/src/Gui/Command.cpp index 624feced5c..f377d28bc8 100644 --- a/src/Gui/Command.cpp +++ b/src/Gui/Command.cpp @@ -64,6 +64,7 @@ #include #include +#include #include FC_LOG_LEVEL_INIT("Command", true, true); diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index ecb90b7a44..8fd1e37247 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 9e749027c9..afeb128b8a 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include "Application.h" diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 1776c94d4b..eeaa528ee2 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include diff --git a/src/Gui/ViewProviderPythonFeature.h b/src/Gui/ViewProviderPythonFeature.h index a84cefbb72..d95ad42a6e 100644 --- a/src/Gui/ViewProviderPythonFeature.h +++ b/src/Gui/ViewProviderPythonFeature.h @@ -25,6 +25,7 @@ #define GUI_VIEWPROVIDERPYTHONFEATURE_H #include +#include #include #include #include diff --git a/src/Gui/propertyeditor/PropertyEditor.cpp b/src/Gui/propertyeditor/PropertyEditor.cpp index 274e178bb0..98ce3ccdbe 100644 --- a/src/Gui/propertyeditor/PropertyEditor.cpp +++ b/src/Gui/propertyeditor/PropertyEditor.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include "MainWindow.h" #include "DlgAddProperty.h" #include "PropertyEditor.h" diff --git a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp index 44f66fa4f3..344a6c6add 100644 --- a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp +++ b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp @@ -31,6 +31,7 @@ #endif #include +#include #include #include #include