335 lines
8.4 KiB
C++
335 lines
8.4 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2009 Werner Mayer <wmayer@users.sourceforge.net> *
|
|
* *
|
|
* 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 <QCoreApplication>
|
|
# include <QObject>
|
|
# include <QEvent>
|
|
# include <QMutex>
|
|
# include <QMutexLocker>
|
|
# include <QSemaphore>
|
|
# include <QThread>
|
|
# include <QWaitCondition>
|
|
#endif
|
|
|
|
#include "DocumentProtector.h"
|
|
|
|
#include <App/Document.h>
|
|
#include <App/DocumentObject.h>
|
|
#include <Base/Exception.h>
|
|
|
|
using namespace Sandbox;
|
|
|
|
|
|
namespace Sandbox {
|
|
|
|
static const int QT_CUSTOM_EVENT_PROTECTOR = 10000;
|
|
|
|
class AbstractCustomProtectorEvent : public QEvent
|
|
{
|
|
public:
|
|
AbstractCustomProtectorEvent()
|
|
: QEvent(QEvent::Type(QT_CUSTOM_EVENT_PROTECTOR)), semaphore(0)
|
|
{
|
|
}
|
|
~AbstractCustomProtectorEvent()
|
|
{
|
|
if (semaphore)
|
|
semaphore->release();
|
|
}
|
|
virtual void execute() = 0;
|
|
|
|
QSemaphore* semaphore;
|
|
};
|
|
|
|
class CustomAddObjectEvent : public AbstractCustomProtectorEvent
|
|
{
|
|
public:
|
|
CustomAddObjectEvent(App::DocumentObject** o, App::Document* d, const std::string& type, const std::string& name)
|
|
: obj(o), doc(d), type(type), name(name)
|
|
{
|
|
}
|
|
~CustomAddObjectEvent()
|
|
{
|
|
}
|
|
void execute()
|
|
{
|
|
*obj = doc->addObject(this->type.c_str(), this->name.c_str());
|
|
}
|
|
|
|
protected:
|
|
App::DocumentObject** obj;
|
|
App::Document* doc;
|
|
std::string type, name;
|
|
};
|
|
|
|
class CustomRemoveObjectEvent : public AbstractCustomProtectorEvent
|
|
{
|
|
public:
|
|
CustomRemoveObjectEvent(App::Document* d, const std::string& n) : doc(d), name(n)
|
|
{
|
|
}
|
|
~CustomRemoveObjectEvent()
|
|
{
|
|
}
|
|
void execute()
|
|
{
|
|
doc->removeObject(this->name.c_str());
|
|
}
|
|
|
|
protected:
|
|
App::Document* doc;
|
|
std::string name;
|
|
};
|
|
|
|
class CustomRecomputeEvent : public AbstractCustomProtectorEvent
|
|
{
|
|
public:
|
|
CustomRecomputeEvent(App::Document* d) : doc(d)
|
|
{
|
|
}
|
|
~CustomRecomputeEvent()
|
|
{
|
|
}
|
|
void execute()
|
|
{
|
|
doc->recompute();
|
|
}
|
|
|
|
protected:
|
|
App::Document* doc;
|
|
};
|
|
|
|
class CustomPropertyEvent : public AbstractCustomProtectorEvent
|
|
{
|
|
public:
|
|
CustomPropertyEvent(App::Property& p, const App::Property& v)
|
|
: property(p), value(v)
|
|
{
|
|
}
|
|
~CustomPropertyEvent()
|
|
{
|
|
}
|
|
void execute()
|
|
{
|
|
property.Paste(value);
|
|
}
|
|
|
|
protected:
|
|
App::Property& property;
|
|
const App::Property& value;
|
|
};
|
|
|
|
class CustomCallableEvent : public AbstractCustomProtectorEvent
|
|
{
|
|
public:
|
|
CustomCallableEvent(const AbstractCallable& call)
|
|
: callable(call)
|
|
{
|
|
}
|
|
~CustomCallableEvent()
|
|
{
|
|
}
|
|
void execute()
|
|
{
|
|
callable();
|
|
}
|
|
|
|
protected:
|
|
const AbstractCallable& callable;
|
|
};
|
|
|
|
class CustomPurgeEvent : public AbstractCustomProtectorEvent
|
|
{
|
|
public:
|
|
CustomPurgeEvent(App::DocumentObject* o)
|
|
: obj(o)
|
|
{
|
|
}
|
|
~CustomPurgeEvent()
|
|
{
|
|
}
|
|
void execute()
|
|
{
|
|
obj->purgeTouched();
|
|
}
|
|
|
|
protected:
|
|
App::DocumentObject* obj;
|
|
};
|
|
|
|
class DocumentReceiver : public QObject
|
|
{
|
|
public:
|
|
DocumentReceiver(QObject *parent = 0) : QObject(parent)
|
|
{
|
|
}
|
|
~DocumentReceiver()
|
|
{
|
|
}
|
|
|
|
static DocumentReceiver *globalInstance();
|
|
|
|
protected:
|
|
void customEvent(QEvent*);
|
|
void postEventAndWait(QEvent*);
|
|
|
|
// friends
|
|
friend class DocumentProtector;
|
|
friend class DocumentObjectProtector;
|
|
};
|
|
|
|
Q_GLOBAL_STATIC(DocumentReceiver, theInstance)
|
|
|
|
DocumentReceiver *DocumentReceiver::globalInstance()
|
|
{
|
|
return theInstance();
|
|
}
|
|
|
|
// Posts an event and waits for it to finish processing
|
|
void DocumentReceiver::postEventAndWait(QEvent* e)
|
|
{
|
|
QThread *currentThread = QThread::currentThread();
|
|
QThread *thr = this->thread(); // this is the main thread
|
|
|
|
if (currentThread == thr) {
|
|
// we're in the main thread
|
|
QCoreApplication::sendEvent(this, e);
|
|
delete e;
|
|
}
|
|
else {
|
|
// NOTE: We send an event to this instance that's why it is important
|
|
// that this object is part of the main thread
|
|
QSemaphore semaphore;
|
|
static_cast<AbstractCustomProtectorEvent*>(e)->semaphore = &semaphore;
|
|
QCoreApplication::postEvent(this, e);
|
|
// wait until the event has been processed
|
|
semaphore.acquire();
|
|
}
|
|
}
|
|
|
|
void DocumentReceiver::customEvent(QEvent* e)
|
|
{
|
|
if ((int)e->type() == QT_CUSTOM_EVENT_PROTECTOR) {
|
|
static_cast<AbstractCustomProtectorEvent*>(e)->execute();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
DocumentProtector::DocumentProtector(App::Document* doc)
|
|
: App::DocumentObserver(doc)
|
|
{
|
|
}
|
|
|
|
DocumentProtector::~DocumentProtector()
|
|
{
|
|
}
|
|
|
|
void DocumentProtector::init()
|
|
{
|
|
// this method must be called somewhere from the main thread
|
|
DocumentReceiver::globalInstance()->
|
|
moveToThread(QCoreApplication::instance()->thread());
|
|
}
|
|
|
|
void DocumentProtector::slotDeletedDocument(const App::Document& Doc)
|
|
{
|
|
if (&Doc == getDocument()) {
|
|
this->detachDocument();
|
|
}
|
|
}
|
|
|
|
void DocumentProtector::validate()
|
|
{
|
|
if (!this->getDocument())
|
|
throw Base::ValueError("Handled document is null");
|
|
}
|
|
|
|
App::DocumentObject *DocumentProtector::addObject(const std::string& type, const std::string& name)
|
|
{
|
|
validate();
|
|
App::DocumentObject* obj;
|
|
DocumentReceiver::globalInstance()->postEventAndWait
|
|
(new CustomAddObjectEvent(&obj, this->getDocument(), type, name));
|
|
return obj;
|
|
}
|
|
|
|
void DocumentProtector::removeObject(const std::string& name)
|
|
{
|
|
validate();
|
|
DocumentReceiver::globalInstance()->postEventAndWait
|
|
(new CustomRemoveObjectEvent(this->getDocument(), name));
|
|
}
|
|
|
|
void DocumentProtector::recompute()
|
|
{
|
|
validate();
|
|
DocumentReceiver::globalInstance()->postEventAndWait
|
|
(new CustomRecomputeEvent(this->getDocument()));
|
|
}
|
|
|
|
// ------------------------------------------
|
|
|
|
DocumentObjectProtector::DocumentObjectProtector(App::DocumentObject* o) : obj(o)
|
|
{
|
|
}
|
|
|
|
DocumentObjectProtector::~DocumentObjectProtector()
|
|
{
|
|
}
|
|
|
|
void DocumentObjectProtector::validate()
|
|
{
|
|
if (!obj)
|
|
throw Base::ValueError("Handled document object is null");
|
|
}
|
|
|
|
App::DocumentObject* DocumentObjectProtector::getObject() const
|
|
{
|
|
return this->obj;
|
|
}
|
|
|
|
bool DocumentObjectProtector::setProperty(const std::string& name, const App::Property& value)
|
|
{
|
|
validate();
|
|
App::Property* prop = obj->getPropertyByName(name.c_str());
|
|
if (!prop)
|
|
return false;
|
|
DocumentReceiver::globalInstance()->postEventAndWait(new CustomPropertyEvent(*prop, value));
|
|
return true;
|
|
}
|
|
|
|
void DocumentObjectProtector::execute(const AbstractCallable& call)
|
|
{
|
|
validate();
|
|
DocumentReceiver::globalInstance()->postEventAndWait(new CustomCallableEvent(call));
|
|
}
|
|
|
|
void DocumentObjectProtector::purgeTouched()
|
|
{
|
|
validate();
|
|
DocumentReceiver::globalInstance()->postEventAndWait(new CustomPurgeEvent(obj));
|
|
}
|