Remove unused code into GUI

This commit is contained in:
andrea
2022-07-11 15:10:25 +02:00
committed by Uwe
parent 094ae93678
commit 3018985f80
47 changed files with 14 additions and 1592 deletions

View File

@@ -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;
}