Remove unused code into GUI
This commit is contained in:
@@ -52,219 +52,6 @@ FC_LOG_LEVEL_INIT("ViewProviderPythonFeature", true, true)
|
||||
using namespace Gui;
|
||||
namespace bp = boost::placeholders;
|
||||
|
||||
// #0003564: Python objects: updateData calls to proxy instance that should have been deleted
|
||||
// See https://forum.freecadweb.org/viewtopic.php?f=22&t=30429&p=252429#p252429
|
||||
#if 0
|
||||
namespace Gui {
|
||||
|
||||
struct ProxyInfo {
|
||||
Py::Object viewObject;
|
||||
Py::Object proxy;
|
||||
|
||||
~ProxyInfo() {
|
||||
Base::PyGILStateLocker lock;
|
||||
viewObject = Py::Object();
|
||||
proxy = Py::Object();
|
||||
}
|
||||
};
|
||||
|
||||
class PropertyEvent : public QEvent
|
||||
{
|
||||
public:
|
||||
PropertyEvent(const Gui::ViewProviderDocumentObject* vp, const ProxyInfo &info)
|
||||
: QEvent(QEvent::Type(QEvent::User)), view(vp), info(info)
|
||||
{
|
||||
}
|
||||
|
||||
const Gui::ViewProviderDocumentObject* view;
|
||||
ProxyInfo info;
|
||||
};
|
||||
|
||||
class ViewProviderPythonFeatureObserver : public QObject
|
||||
{
|
||||
public:
|
||||
/// The one and only instance.
|
||||
static ViewProviderPythonFeatureObserver* instance();
|
||||
/// Destructs the sole instance.
|
||||
static void destruct ();
|
||||
void slotAppendObject(const Gui::ViewProvider&);
|
||||
void slotDeleteObject(const Gui::ViewProvider&);
|
||||
void slotDeleteDocument(const Gui::Document&);
|
||||
|
||||
private:
|
||||
void customEvent(QEvent* e)
|
||||
{
|
||||
PropertyEvent* pe = static_cast<PropertyEvent*>(e);
|
||||
std::set<const Gui::ViewProvider*>::iterator it = viewMap.find(pe->view);
|
||||
// Make sure that the object hasn't been deleted in the meantime (#0001522)
|
||||
if (it != viewMap.end()) {
|
||||
viewMap.erase(it);
|
||||
|
||||
// We check below the python object of the view provider to make
|
||||
// sure that the view provider is actually the owner of the proxy
|
||||
// object we cached before. This step is necessary to prevent a
|
||||
// very obscure bug described here.
|
||||
//
|
||||
// The proxy caching is only effective when an object is deleted in
|
||||
// an event of undo, and we restore the proxy in the event of redo.
|
||||
// The object is not really freed while inside undo/redo stack. It
|
||||
// gets really deleted from memory when either the user clears the
|
||||
// undo/redo stack manually, or the redo stack gets automatically
|
||||
// cleared when new transaction is created. FC has no explicit
|
||||
// signaling of when the object is really deleted from the memory.
|
||||
// This ViewProviderPythonFeatureObserver uses a heuristic to
|
||||
// decide when to flush the cache in slotAppendObject(), that is,
|
||||
// it sees any cache miss event as the signaling of an redo clear.
|
||||
// The bug happens in the very rare event, when the redo stack is
|
||||
// cleared when new transaction is added, and the freed object's
|
||||
// memory gets immediately reused by c++ allocator for the new
|
||||
// object created in the new transaction. This creates a cache
|
||||
// false hit event, where the old deleted view provider's proxy
|
||||
// gets mistakenly assigned to the newly created object, which
|
||||
// happens to have the exact same memory location. This situation
|
||||
// is very rare and really depends on the system's allocator
|
||||
// implementation. However, tests show that it happens regularly
|
||||
// in Linux debug build. To prevent this, we use the trick of
|
||||
// checking the python object pointer of the view provider to make
|
||||
// sure the view provider are in fact the same. We hold the python
|
||||
// object reference count, so it never gets freed and reused like
|
||||
// its owner view provider.
|
||||
//
|
||||
// Side note: the original implementation uses property copy and
|
||||
// paste to store the proxy object, which is fine, but has the
|
||||
// trouble of having to manually freed the copied property. And the
|
||||
// original implementation didn't do that in every case, causing
|
||||
// memory leak. We now simply stores the python object with
|
||||
// reference counting, so no need to worry about deleting
|
||||
|
||||
Py::Object viewObject(const_cast<ViewProviderDocumentObject*>(pe->view)->getPyObject(),true);
|
||||
if(viewObject.ptr() != pe->info.viewObject.ptr()) {
|
||||
if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG))
|
||||
FC_WARN("invalid proxy cache " << viewObject.ptr() << ", " <<
|
||||
pe->info.viewObject.ptr() << ", " << pe->info.proxy.ptr());
|
||||
}else{
|
||||
App::Property* prop = pe->view->getPropertyByName("Proxy");
|
||||
if (prop && prop->isDerivedFrom(App::PropertyPythonObject::getClassTypeId())) {
|
||||
prop->setPyObject(pe->info.proxy.ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static ViewProviderPythonFeatureObserver* _singleton;
|
||||
|
||||
ViewProviderPythonFeatureObserver();
|
||||
~ViewProviderPythonFeatureObserver();
|
||||
typedef std::map<
|
||||
const App::DocumentObject*,
|
||||
ProxyInfo
|
||||
> ObjectProxy;
|
||||
|
||||
std::map<const App::Document*, ObjectProxy> proxyMap;
|
||||
std::set<const Gui::ViewProvider*> viewMap;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
ViewProviderPythonFeatureObserver* ViewProviderPythonFeatureObserver::_singleton = 0;
|
||||
|
||||
ViewProviderPythonFeatureObserver* ViewProviderPythonFeatureObserver::instance()
|
||||
{
|
||||
if (!_singleton)
|
||||
_singleton = new ViewProviderPythonFeatureObserver;
|
||||
return _singleton;
|
||||
}
|
||||
|
||||
void ViewProviderPythonFeatureObserver::destruct ()
|
||||
{
|
||||
delete _singleton;
|
||||
_singleton = 0;
|
||||
}
|
||||
|
||||
void ViewProviderPythonFeatureObserver::slotDeleteDocument(const Gui::Document& d)
|
||||
{
|
||||
App::Document* doc = d.getDocument();
|
||||
std::map<const App::Document*, ObjectProxy>::iterator it = proxyMap.find(doc);
|
||||
if (it != proxyMap.end()) {
|
||||
Base::PyGILStateLocker lock;
|
||||
proxyMap.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewProviderPythonFeatureObserver::slotAppendObject(const Gui::ViewProvider& obj)
|
||||
{
|
||||
if (!obj.isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId()))
|
||||
return;
|
||||
const Gui::ViewProviderDocumentObject& vp = static_cast<const Gui::ViewProviderDocumentObject&>(obj);
|
||||
const App::DocumentObject* docobj = vp.getObject();
|
||||
App::Document* doc = docobj->getDocument();
|
||||
std::map<const App::Document*, ObjectProxy>::iterator it = proxyMap.find(doc);
|
||||
if (it != proxyMap.end()) {
|
||||
ObjectProxy::iterator jt = it->second.find(docobj);
|
||||
if (jt != it->second.end()) {
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
App::Property* prop = vp.getPropertyByName("Proxy");
|
||||
if (prop && prop->isDerivedFrom(App::PropertyPythonObject::getClassTypeId())) {
|
||||
// make this delayed so that the corresponding item in the tree view is accessible
|
||||
QApplication::postEvent(this, new PropertyEvent(&vp, jt->second));
|
||||
// needed in customEvent()
|
||||
viewMap.insert(&vp);
|
||||
it->second.erase(jt);
|
||||
}
|
||||
}
|
||||
catch (Py::Exception& e) {
|
||||
e.clear();
|
||||
}
|
||||
}
|
||||
// all cached objects of the documents are already destroyed
|
||||
else {
|
||||
it->second.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ViewProviderPythonFeatureObserver::slotDeleteObject(const Gui::ViewProvider& obj)
|
||||
{
|
||||
// check this in customEvent() if the object is still there
|
||||
std::set<const Gui::ViewProvider*>::iterator it = viewMap.find(&obj);
|
||||
if (it != viewMap.end())
|
||||
viewMap.erase(it);
|
||||
if (!obj.isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId()))
|
||||
return;
|
||||
const Gui::ViewProviderDocumentObject& vp = static_cast<const Gui::ViewProviderDocumentObject&>(obj);
|
||||
const App::DocumentObject* docobj = vp.getObject();
|
||||
App::Document* doc = docobj->getDocument();
|
||||
if (!doc->getUndoMode())
|
||||
return; // object will be deleted immediately, thus we don't need to store anything
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
App::Property* prop = vp.getPropertyByName("Proxy");
|
||||
if (prop && prop->isDerivedFrom(App::PropertyPythonObject::getClassTypeId())) {
|
||||
auto &info = proxyMap[doc][docobj];
|
||||
info.viewObject = Py::asObject(const_cast<ViewProviderDocumentObject&>(vp).getPyObject());
|
||||
info.proxy = Py::asObject(prop->getPyObject());
|
||||
FC_LOG("proxy cache " << info.viewObject.ptr() << ", " << info.proxy.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception& e) {
|
||||
e.clear();
|
||||
}
|
||||
}
|
||||
|
||||
ViewProviderPythonFeatureObserver::ViewProviderPythonFeatureObserver()
|
||||
{
|
||||
Gui::Application::Instance->signalDeletedObject.connect(boost::bind
|
||||
(&ViewProviderPythonFeatureObserver::slotDeleteObject, this, bp::_1));
|
||||
Gui::Application::Instance->signalNewObject.connect(boost::bind
|
||||
(&ViewProviderPythonFeatureObserver::slotAppendObject, this, bp::_1));
|
||||
Gui::Application::Instance->signalDeleteDocument.connect(boost::bind
|
||||
(&ViewProviderPythonFeatureObserver::slotDeleteDocument, this, bp::_1));
|
||||
}
|
||||
|
||||
ViewProviderPythonFeatureObserver::~ViewProviderPythonFeatureObserver()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -272,9 +59,6 @@ ViewProviderPythonFeatureImp::ViewProviderPythonFeatureImp(
|
||||
ViewProviderDocumentObject* vp, App::PropertyPythonObject &proxy)
|
||||
: object(vp), Proxy(proxy), has__object__(false)
|
||||
{
|
||||
#if 0
|
||||
(void)ViewProviderPythonFeatureObserver::instance();
|
||||
#endif
|
||||
}
|
||||
|
||||
ViewProviderPythonFeatureImp::~ViewProviderPythonFeatureImp()
|
||||
@@ -307,9 +91,6 @@ QIcon ViewProviderPythonFeatureImp::getIcon() const
|
||||
{
|
||||
_FC_PY_CALL_CHECK(getIcon,return(QIcon()));
|
||||
|
||||
// default icon
|
||||
//static QPixmap px = BitmapFactory().pixmap("Tree_Python");
|
||||
|
||||
// Run the getIcon method of the proxy object.
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
@@ -366,7 +147,6 @@ QIcon ViewProviderPythonFeatureImp::getIcon() const
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
return QIcon();
|
||||
}
|
||||
|
||||
@@ -966,8 +746,6 @@ bool ViewProviderPythonFeatureImp::getDefaultDisplayMode(std::string &mode) cons
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::String str(Base::pyCall(py_getDefaultDisplayMode.ptr()));
|
||||
//if (str.isUnicode())
|
||||
// str = str.encode("ascii"); // json converts strings into unicode
|
||||
mode = str.as_std_string("ascii");
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user