DocumentProtector.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2009 Werner Mayer <wmayer@users.sourceforge.net>        *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <QCoreApplication>
00027 # include <QObject>
00028 # include <QEvent>
00029 # include <QMutex>
00030 # include <QMutexLocker>
00031 # include <QSemaphore>
00032 # include <QThread>
00033 # include <QWaitCondition>
00034 #endif
00035 
00036 #include "DocumentProtector.h"
00037 
00038 #include <App/Document.h>
00039 #include <App/DocumentObject.h>
00040 #include <Base/Exception.h>
00041 
00042 using namespace Sandbox;
00043 
00044 
00045 namespace Sandbox {
00046 
00047 static const int QT_CUSTOM_EVENT_PROTECTOR = 10000;
00048 
00049 class AbstractCustomProtectorEvent : public QEvent
00050 {
00051 public:
00052     AbstractCustomProtectorEvent()
00053         : QEvent(QEvent::Type(QT_CUSTOM_EVENT_PROTECTOR)), semaphore(0)
00054     {
00055     }
00056     ~AbstractCustomProtectorEvent()
00057     {
00058         if (semaphore)
00059             semaphore->release();
00060     }
00061     virtual void execute() = 0;
00062 
00063     QSemaphore* semaphore;
00064 };
00065 
00066 class CustomAddObjectEvent : public AbstractCustomProtectorEvent
00067 {
00068 public:
00069     CustomAddObjectEvent(App::DocumentObject** o, App::Document* d, const std::string& type, const std::string& name)
00070         : obj(o), doc(d), type(type), name(name)
00071     {
00072     }
00073     ~CustomAddObjectEvent()
00074     {
00075     }
00076     void execute()
00077     {
00078         *obj = doc->addObject(this->type.c_str(), this->name.c_str());
00079     }
00080 
00081 protected:
00082     App::DocumentObject** obj;
00083     App::Document* doc;
00084     std::string type, name;
00085 };
00086 
00087 class CustomRemoveObjectEvent : public AbstractCustomProtectorEvent
00088 {
00089 public:
00090     CustomRemoveObjectEvent(App::Document* d, const std::string& n) : doc(d), name(n)
00091     {
00092     }
00093     ~CustomRemoveObjectEvent()
00094     {
00095     }
00096     void execute()
00097     {
00098         doc->remObject(this->name.c_str());
00099     }
00100 
00101 protected:
00102     App::Document* doc;
00103     std::string name;
00104 };
00105 
00106 class CustomRecomputeEvent : public AbstractCustomProtectorEvent
00107 {
00108 public:
00109     CustomRecomputeEvent(App::Document* d) : doc(d)
00110     {
00111     }
00112     ~CustomRecomputeEvent()
00113     {
00114     }
00115     void execute()
00116     {
00117         doc->recompute();
00118     }
00119 
00120 protected:
00121     App::Document* doc;
00122 };
00123 
00124 class CustomPropertyEvent : public AbstractCustomProtectorEvent
00125 {
00126 public:
00127     CustomPropertyEvent(App::Property& p, const App::Property& v)
00128       : property(p), value(v)
00129     {
00130     }
00131     ~CustomPropertyEvent()
00132     {
00133     }
00134     void execute()
00135     {
00136         property.Paste(value);
00137     }
00138 
00139 protected:
00140     App::Property& property;
00141     const App::Property& value;
00142 };
00143 
00144 class CustomCallableEvent : public AbstractCustomProtectorEvent
00145 {
00146 public:
00147     CustomCallableEvent(const AbstractCallable& call)
00148       : callable(call)
00149     {
00150     }
00151     ~CustomCallableEvent()
00152     {
00153     }
00154     void execute()
00155     {
00156         callable();
00157     }
00158 
00159 protected:
00160     const AbstractCallable& callable;
00161 };
00162 
00163 class DocumentReceiver : public QObject
00164 {
00165 public:
00166     DocumentReceiver(QObject *parent = 0) : QObject(parent)
00167     {
00168     }
00169     ~DocumentReceiver()
00170     {
00171     }
00172 
00173     static DocumentReceiver *globalInstance();
00174 
00175 protected:
00176     void customEvent(QEvent*);
00177     void postEventAndWait(QEvent*);
00178 
00179     // friends
00180     friend class DocumentProtector;
00181     friend class DocumentObjectProtector;
00182 };
00183 
00184 Q_GLOBAL_STATIC(DocumentReceiver, theInstance)
00185 
00186 DocumentReceiver *DocumentReceiver::globalInstance()
00187 {
00188     return theInstance();
00189 }
00190 
00191 // Posts an event and waits for it to finish processing
00192 void DocumentReceiver::postEventAndWait(QEvent* e)
00193 {
00194     QThread *currentThread = QThread::currentThread();
00195     QThread *thr = this->thread(); // this is the main thread
00196 
00197     if (currentThread == thr) {
00198         // we're in the main thread
00199         QCoreApplication::sendEvent(this, e);
00200         delete e;
00201     }
00202     else {
00203         // NOTE: We send an event to this instance that's why it is important
00204         // that this object is part of the main thread
00205         QSemaphore semaphore;
00206         static_cast<AbstractCustomProtectorEvent*>(e)->semaphore = &semaphore;
00207         QCoreApplication::postEvent(this, e);
00208         // wait until the event has been processed
00209         semaphore.acquire();
00210     }
00211 }
00212 
00213 void DocumentReceiver::customEvent(QEvent* e)
00214 {
00215     if ((int)e->type() == QT_CUSTOM_EVENT_PROTECTOR) {
00216         static_cast<AbstractCustomProtectorEvent*>(e)->execute();
00217     }
00218 }
00219 
00220 }
00221 
00222 DocumentProtector::DocumentProtector(App::Document* doc)
00223   : App::DocumentObserver(doc)
00224 {
00225 }
00226 
00227 DocumentProtector::~DocumentProtector()
00228 {
00229 }
00230 
00231 void DocumentProtector::init()
00232 {
00233     // this method must be called somewhere from the main thread
00234     DocumentReceiver::globalInstance()->
00235         moveToThread(QCoreApplication::instance()->thread());
00236 }
00237 
00238 void DocumentProtector::slotCreatedDocument(const App::Document& Doc)
00239 {
00240 }
00241 
00242 void DocumentProtector::slotDeletedDocument(const App::Document& Doc)
00243 {
00244     if (&Doc == getDocument()) {
00245         this->detachDocument();
00246     }
00247 }
00248 
00249 void DocumentProtector::slotCreatedObject(const App::DocumentObject& Obj)
00250 {
00251 }
00252 
00253 void DocumentProtector::slotDeletedObject(const App::DocumentObject& Obj)
00254 {
00255 }
00256 
00257 void DocumentProtector::slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop)
00258 {
00259 }
00260 
00261 void DocumentProtector::validate()
00262 {
00263     if (!this->getDocument())
00264         throw Base::Exception("Handled document is null");
00265 }
00266 
00267 App::DocumentObject *DocumentProtector::addObject(const std::string& type, const std::string& name)
00268 {
00269     validate();
00270     App::DocumentObject* obj;
00271     DocumentReceiver::globalInstance()->postEventAndWait
00272         (new CustomAddObjectEvent(&obj, this->getDocument(), type, name));
00273     return obj;
00274 }
00275 
00276 void DocumentProtector::removeObject(const std::string& name)
00277 {
00278     validate();
00279     DocumentReceiver::globalInstance()->postEventAndWait
00280         (new CustomRemoveObjectEvent(this->getDocument(), name));
00281 }
00282 
00283 void DocumentProtector::recompute()
00284 {
00285     validate();
00286     DocumentReceiver::globalInstance()->postEventAndWait
00287         (new CustomRecomputeEvent(this->getDocument()));
00288 }
00289 
00290 // ------------------------------------------
00291 
00292 DocumentObjectProtector::DocumentObjectProtector(App::DocumentObject* o) : obj(o)
00293 {
00294 }
00295 
00296 DocumentObjectProtector::~DocumentObjectProtector()
00297 {
00298 }
00299 
00300 void DocumentObjectProtector::validate()
00301 {
00302     if (!obj)
00303         throw Base::Exception("Handled document object is null");
00304 }
00305 
00306 App::DocumentObject* DocumentObjectProtector::getObject() const
00307 {
00308     return this->obj;
00309 }
00310 
00311 bool DocumentObjectProtector::setProperty(const std::string& name, const App::Property& value)
00312 {
00313     validate();
00314     App::Property* prop = obj->getPropertyByName(name.c_str());
00315     if (!prop)
00316         return false;
00317     DocumentReceiver::globalInstance()->postEventAndWait(new CustomPropertyEvent(*prop, value));
00318     return true;
00319 }
00320 
00321 void DocumentObjectProtector::execute(const AbstractCallable& call)
00322 {
00323     validate();
00324     DocumentReceiver::globalInstance()->postEventAndWait(new CustomCallableEvent(call));
00325 }
00326 

Generated on Wed Nov 23 19:00:08 2011 for FreeCAD by  doxygen 1.6.1