From 2d8c5b7870829f65b4ebdf17dcbf6f7a9ac458e1 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 3 Sep 2015 19:09:03 +0200 Subject: [PATCH] + implement auto-save function for documents --- src/Gui/Application.cpp | 3 + src/Gui/AutoSaver.cpp | 140 +++++++++++++++++++++++++ src/Gui/AutoSaver.h | 71 +++++++++++++ src/Gui/CMakeLists.txt | 3 + src/Mod/Sandbox/App/DocumentThread.cpp | 39 +++++++ src/Mod/Sandbox/App/DocumentThread.h | 13 +++ src/Mod/Sandbox/Gui/Command.cpp | 29 +++++ src/Mod/Sandbox/Gui/Workbench.cpp | 3 +- 8 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 src/Gui/AutoSaver.cpp create mode 100644 src/Gui/AutoSaver.h diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 9fca972971..36552fdeab 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -62,6 +62,7 @@ #include #include "Application.h" +#include "AutoSaver.h" #include "GuiApplicationNativeEventAware.h" #include "MainWindow.h" #include "Document.h" @@ -1695,6 +1696,8 @@ void Application::runApplication(void) MainWindow mw; mw.setWindowTitle(mainApp.applicationName()); + AutoSaver::instance()->setTimeout(3); + // set toolbar icon size ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("General"); int size = hGrp->GetInt("ToolbarIconSize", 0); diff --git a/src/Gui/AutoSaver.cpp b/src/Gui/AutoSaver.cpp new file mode 100644 index 0000000000..9a4512699e --- /dev/null +++ b/src/Gui/AutoSaver.cpp @@ -0,0 +1,140 @@ +/*************************************************************************** + * Copyright (c) 2010 Werner Mayer * + * * + * 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" + +#ifndef _PreComp_ +# include +# include +#endif + +#include "AutoSaver.h" +#include +#include +#include +#include +#include +#include + +#include "WaitCursor.h" + +using namespace Gui; + +AutoSaver* AutoSaver::self = 0; + +AutoSaver::AutoSaver(QObject* parent) + : QObject(parent), timeout(5) +{ + App::GetApplication().signalNewDocument.connect(boost::bind(&AutoSaver::slotCreateDocument, this, _1)); + App::GetApplication().signalDeleteDocument.connect(boost::bind(&AutoSaver::slotDeleteDocument, this, _1)); +} + +AutoSaver::~AutoSaver() +{ +} + +AutoSaver* AutoSaver::instance() +{ + if (!self) + self = new AutoSaver(QApplication::instance()); + return self; +} + +void AutoSaver::setTimeout(int s) +{ + timeout = Base::clamp(s, 0, 30); +} + +void AutoSaver::slotCreateDocument(const App::Document& Doc) +{ + std::string name = Doc.getName(); + if (timeout > 0) { + int id = startTimer(timeout * 60000); + timerMap[name] = id; + } +} + +void AutoSaver::slotDeleteDocument(const App::Document& Doc) +{ + std::string name = Doc.getName(); + std::map::iterator it = timerMap.find(name); + if (it != timerMap.end()) { + killTimer(it->second); + timerMap.erase(it); + } +} + +void AutoSaver::saveDocument(const std::string& name) +{ + Gui::WaitCursor wc; + App::Document* doc = App::GetApplication().getDocument(name.c_str()); + if (doc) { + std::string fn = doc->TransientDir.getValue(); + fn += "/fc_autosave_file.fcstd"; + Base::FileInfo tmp(fn); + + // make sure to tmp. disable saving thumbnails because this causes trouble if the + // associated 3d view is not active + Base::Reference hGrp = App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Document"); + bool save = hGrp->GetBool("SaveThumbnail",false); + hGrp->SetBool("SaveThumbnail",false); + + // open extra scope to close ZipWriter properly + { + Base::ofstream file(tmp, std::ios::out | std::ios::binary); + Base::ZipWriter writer(file); + + writer.setComment("FreeCAD Document"); + writer.setLevel(0); + writer.putNextEntry("Document.xml"); + + doc->Save(writer); + + // Special handling for Gui document. + doc->signalSaveDocument(writer); + + // write additional files + writer.writeFiles(); + } + hGrp->SetBool("SaveThumbnail",save); + } +} + +void AutoSaver::timerEvent(QTimerEvent * event) +{ + int id = event->timerId(); + for (std::map::iterator it = timerMap.begin(); it != timerMap.end(); ++it) { + if (it->second == id) { + try { + saveDocument(it->first); + break; + } + catch (...) { + Base::Console().Error("Failed to auto-save document '%s'\n", it->first.c_str()); + } + } + } +} + +#include "moc_AutoSaver.cpp" diff --git a/src/Gui/AutoSaver.h b/src/Gui/AutoSaver.h new file mode 100644 index 0000000000..adf9e944e0 --- /dev/null +++ b/src/Gui/AutoSaver.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (c) 2010 Werner Mayer * + * * + * 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 GUI_AUTOSAVER_H +#define GUI_AUTOSAVER_H + +#include +#include +#include + +namespace App { +class Document; +} + +namespace Gui { + +/*! + The class AutoSaver is used to automatically save a document to a temporary file. + @author Werner Mayer + */ +class AutoSaver : public QObject +{ + Q_OBJECT + +private: + static AutoSaver* self; + AutoSaver(QObject* parent); + virtual ~AutoSaver(); + +public: + static AutoSaver* instance(); + /*! + Sets the timeout in minutes. A value of 0 means that no timer is used. + */ + void setTimeout(int s); + +protected: + void slotCreateDocument(const App::Document& Doc); + void slotDeleteDocument(const App::Document& Doc); + void timerEvent(QTimerEvent * event); + void saveDocument(const std::string&); + +private: + int timeout; /*!< Timeout in minutes */ + std::map timerMap; +}; + +} //namespace Gui + + +#endif //GUI_AUTOSAVER_H diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 24d4182d8c..8655b851ac 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -155,6 +155,7 @@ set(Gui_MOC_HDRS Action.h ActionFunction.h Assistant.h + AutoSaver.h CallTips.h CombiView.h Control.h @@ -955,6 +956,7 @@ SOURCE_GROUP("Selection" FILES ${Selection_SRCS}) SET(FreeCADGui_CPP_SRCS Application.cpp ApplicationPy.cpp + AutoSaver.cpp BitmapFactory.cpp Document.cpp DocumentModel.cpp @@ -975,6 +977,7 @@ SET(FreeCADGui_CPP_SRCS ) SET(FreeCADGui_SRCS Application.h + AutoSaver.h BitmapFactory.h Document.h DocumentModel.h diff --git a/src/Mod/Sandbox/App/DocumentThread.cpp b/src/Mod/Sandbox/App/DocumentThread.cpp index 5df40b2aab..7f13cb3048 100644 --- a/src/Mod/Sandbox/App/DocumentThread.cpp +++ b/src/Mod/Sandbox/App/DocumentThread.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -229,3 +230,41 @@ void DocumentTestThread::run() dp.recompute(); op.execute(Callable(obj)); } + + +DocumentSaverThread::DocumentSaverThread(App::Document* doc, QObject* parent) + : QThread(parent), doc(doc) +{ +} + +DocumentSaverThread::~DocumentSaverThread() +{ +} + +void DocumentSaverThread::run() +{ + std::string uuid = Base::Uuid::createUuid(); + std::string fn = doc->TransientDir.getValue(); + fn += "/"; + fn += uuid; + fn += ".autosave"; + Base::FileInfo tmp(fn); + + // open extra scope to close ZipWriter properly + { + Base::ofstream file(tmp, std::ios::out | std::ios::binary); + Base::ZipWriter writer(file); + + writer.setComment("FreeCAD Document"); + writer.setLevel(0); + writer.putNextEntry("Document.xml"); + + doc->Save(writer); + + // Special handling for Gui document. + doc->signalSaveDocument(writer); + + // write additional files + writer.writeFiles(); + } +} diff --git a/src/Mod/Sandbox/App/DocumentThread.h b/src/Mod/Sandbox/App/DocumentThread.h index 5d22069802..b8329c38c8 100644 --- a/src/Mod/Sandbox/App/DocumentThread.h +++ b/src/Mod/Sandbox/App/DocumentThread.h @@ -113,6 +113,19 @@ protected: void run(); }; +class SandboxAppExport DocumentSaverThread : public QThread +{ +public: + DocumentSaverThread(App::Document* doc, QObject* parent=0); + ~DocumentSaverThread(); + +protected: + void run(); + +private: + App::Document* doc; +}; + } #endif // SANDBOX_DOCUMENTTHREAD_H diff --git a/src/Mod/Sandbox/Gui/Command.cpp b/src/Mod/Sandbox/Gui/Command.cpp index bb43824803..3592f8516b 100644 --- a/src/Mod/Sandbox/Gui/Command.cpp +++ b/src/Mod/Sandbox/Gui/Command.cpp @@ -130,6 +130,34 @@ void CmdSandboxDocumentTestThread::activated(int iMsg) // ------------------------------------------------------------------------------- +DEF_STD_CMD_A(CmdSandboxDocumentSaveThread); + +CmdSandboxDocumentSaveThread::CmdSandboxDocumentSaveThread() + :Command("Sandbox_SaveThread") +{ + sAppModule = "Sandbox"; + sGroup = QT_TR_NOOP("Sandbox"); + sMenuText = QT_TR_NOOP("Save thread"); + sToolTipText = QT_TR_NOOP("Sandbox save function"); + sWhatsThis = QT_TR_NOOP("Sandbox save function"); + sStatusTip = QT_TR_NOOP("Sandbox save function"); +} + +void CmdSandboxDocumentSaveThread::activated(int iMsg) +{ + App::Document* doc = App::GetApplication().getActiveDocument(); + Sandbox::DocumentSaverThread* dt = new Sandbox::DocumentSaverThread(doc); + QObject::connect(dt, SIGNAL(finished()), dt, SLOT(deleteLater())); + dt->start(); +} + +bool CmdSandboxDocumentSaveThread::isActive() +{ + return App::GetApplication().getActiveDocument() != 0; +} + +// ------------------------------------------------------------------------------- + DEF_STD_CMD(CmdSandboxDocThreadWithSeq); CmdSandboxDocThreadWithSeq::CmdSandboxDocThreadWithSeq() @@ -1410,6 +1438,7 @@ void CreateSandboxCommands(void) Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdSandboxDocumentThread()); rcCmdMgr.addCommand(new CmdSandboxDocumentTestThread()); + rcCmdMgr.addCommand(new CmdSandboxDocumentSaveThread()); rcCmdMgr.addCommand(new CmdSandboxDocThreadWithSeq()); rcCmdMgr.addCommand(new CmdSandboxDocThreadBusy()); rcCmdMgr.addCommand(new CmdSandboxDocumentNoThread()); diff --git a/src/Mod/Sandbox/Gui/Workbench.cpp b/src/Mod/Sandbox/Gui/Workbench.cpp index 8b19e06f26..9f732814e8 100644 --- a/src/Mod/Sandbox/Gui/Workbench.cpp +++ b/src/Mod/Sandbox/Gui/Workbench.cpp @@ -84,7 +84,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const *threads << "Sandbox_PythonLockThread" << "Sandbox_NolockPython" << "Sandbox_PyQtThread" << "Sandbox_PythonThread" << "Sandbox_PythonMainThread"; test->setCommand("Threads"); - *test << "Sandbox_Thread" << "Sandbox_TestThread" << "Sandbox_WorkerThread" << "Sandbox_SeqThread" + *test << "Sandbox_Thread" << "Sandbox_TestThread" << "Sandbox_SaveThread" + << "Sandbox_WorkerThread" << "Sandbox_SeqThread" << "Sandbox_BlockThread" << "Sandbox_NoThread" << threads << "Separator" << "Sandbox_Dialog" << "Sandbox_FileDialog"; Gui::MenuItem* misc = new Gui::MenuItem;