Selection.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) Juergen Riegel         <juergen.riegel@web.de>          *
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 
00026 #ifndef _PreComp_
00027 # include <assert.h>
00028 # include <string>
00029 # include <boost/signals.hpp>
00030 # include <boost/bind.hpp>
00031 # include <QApplication>
00032 # include <QString>
00033 # include <QStatusBar>
00034 #endif
00035 
00037 #include "Application.h"
00038 #include "Document.h"
00039 #include "Selection.h"
00040 #include "SelectionFilter.h"
00041 #include "SelectionObjectPy.h"
00042 #include "View3DInventor.h"
00043 #include <Base/Exception.h>
00044 #include <Base/Console.h>
00045 #include <Base/Interpreter.h>
00046 #include <App/Application.h>
00047 #include <App/Document.h>
00048 #include <App/DocumentObject.h>
00049 #include <App/DocumentObjectPy.h>
00050 #include "MainWindow.h"
00051 
00052 
00053 
00054 using namespace Gui;
00055 using namespace std;
00056 
00057 SelectionObserver::SelectionObserver()
00058 {
00059     attachSelection();
00060 }
00061 
00062 SelectionObserver::~SelectionObserver()
00063 {
00064     detachSelection();
00065 }
00066 
00067 bool SelectionObserver::blockConnection(bool block)
00068 {
00069     bool ok = connectSelection.blocked();
00070     if (block)
00071         connectSelection.block();
00072     else
00073         connectSelection.unblock();
00074     return ok;
00075 }
00076 
00077 bool SelectionObserver::isConnectionBlocked() const
00078 {
00079     return connectSelection.blocked();
00080 }
00081 
00082 void SelectionObserver::attachSelection()
00083 {
00084     if (!connectSelection.connected()) {
00085         connectSelection = Selection().signalSelectionChanged.connect(boost::bind
00086             (&SelectionObserver::onSelectionChanged, this, _1));
00087     }
00088 }
00089 
00090 void SelectionObserver::detachSelection()
00091 {
00092     if (connectSelection.connected()) {
00093         connectSelection.disconnect();
00094     }
00095 }
00096 
00097 // -------------------------------------------
00098 
00099 std::vector<SelectionObserverPython*> SelectionObserverPython::_instances;
00100 
00101 SelectionObserverPython::SelectionObserverPython(const Py::Object& obj) : inst(obj)
00102 {
00103 }
00104 
00105 SelectionObserverPython::~SelectionObserverPython()
00106 {
00107 }
00108 
00109 void SelectionObserverPython::addObserver(const Py::Object& obj)
00110 {
00111     _instances.push_back(new SelectionObserverPython(obj));
00112 }
00113 
00114 void SelectionObserverPython::removeObserver(const Py::Object& obj)
00115 {
00116     SelectionObserverPython* obs=0;
00117     for (std::vector<SelectionObserverPython*>::iterator it =
00118         _instances.begin(); it != _instances.end(); ++it) {
00119         if ((*it)->inst == obj) {
00120             obs = *it;
00121             _instances.erase(it);
00122             break;
00123         }
00124     }
00125 
00126     delete obs;
00127 }
00128 
00129 void SelectionObserverPython::onSelectionChanged(const SelectionChanges& msg)
00130 {
00131     switch (msg.Type)
00132     {
00133     case SelectionChanges::AddSelection:
00134         addSelection(msg);
00135         break;
00136     case SelectionChanges::RmvSelection:
00137         removeSelection(msg);
00138         break;
00139     case SelectionChanges::SetSelection:
00140         setSelection(msg);
00141         break;
00142     case SelectionChanges::ClrSelection:
00143         clearSelection(msg);
00144         break;
00145     case SelectionChanges::SetPreselect:
00146         setPreselection(msg);
00147         break;
00148     case SelectionChanges::RmvPreselect:
00149         removePreselection(msg);
00150         break;
00151     default:
00152         break;
00153     }
00154 }
00155 
00156 void SelectionObserverPython::addSelection(const SelectionChanges& msg)
00157 {
00158     Base::PyGILStateLocker lock;
00159     try {
00160         if (this->inst.hasAttr(std::string("addSelection"))) {
00161             Py::Callable method(this->inst.getAttr(std::string("addSelection")));
00162             Py::Tuple args(4);
00163             args.setItem(0, Py::String(msg.pDocName ? msg.pDocName : ""));
00164             args.setItem(1, Py::String(msg.pObjectName ? msg.pObjectName : ""));
00165             args.setItem(2, Py::String(msg.pSubName ? msg.pSubName : ""));
00166             Py::Tuple tuple(3);
00167             tuple[0] = Py::Float(msg.x);
00168             tuple[1] = Py::Float(msg.y);
00169             tuple[2] = Py::Float(msg.z);
00170             args.setItem(3, tuple);
00171             method.apply(args);
00172         }
00173     }
00174     catch (Py::Exception&) {
00175         Base::PyException e; // extract the Python error text
00176         Base::Console().Error("%s\n", e.what());
00177     }
00178 }
00179 
00180 void SelectionObserverPython::removeSelection(const SelectionChanges& msg)
00181 {
00182     Base::PyGILStateLocker lock;
00183     try {
00184         if (this->inst.hasAttr(std::string("removeSelection"))) {
00185             Py::Callable method(this->inst.getAttr(std::string("removeSelection")));
00186             Py::Tuple args(3);
00187             args.setItem(0, Py::String(msg.pDocName ? msg.pDocName : ""));
00188             args.setItem(1, Py::String(msg.pObjectName ? msg.pObjectName : ""));
00189             args.setItem(2, Py::String(msg.pSubName ? msg.pSubName : ""));
00190             method.apply(args);
00191         }
00192     }
00193     catch (Py::Exception&) {
00194         Base::PyException e; // extract the Python error text
00195         Base::Console().Error("%s\n", e.what());
00196     }
00197 }
00198 
00199 void SelectionObserverPython::setSelection(const SelectionChanges& msg)
00200 {
00201     Base::PyGILStateLocker lock;
00202     try {
00203         if (this->inst.hasAttr(std::string("setSelection"))) {
00204             Py::Callable method(this->inst.getAttr(std::string("setSelection")));
00205             Py::Tuple args(1);
00206             args.setItem(0, Py::String(msg.pDocName ? msg.pDocName : ""));
00207             method.apply(args);
00208         }
00209     }
00210     catch (Py::Exception&) {
00211         Base::PyException e; // extract the Python error text
00212         Base::Console().Error("%s\n", e.what());
00213     }
00214 }
00215 
00216 void SelectionObserverPython::clearSelection(const SelectionChanges& msg)
00217 {
00218     Base::PyGILStateLocker lock;
00219     try {
00220         if (this->inst.hasAttr(std::string("clearSelection"))) {
00221             Py::Callable method(this->inst.getAttr(std::string("clearSelection")));
00222             Py::Tuple args(1);
00223             args.setItem(0, Py::String(msg.pDocName ? msg.pDocName : ""));
00224             method.apply(args);
00225         }
00226     }
00227     catch (Py::Exception&) {
00228         Base::PyException e; // extract the Python error text
00229         Base::Console().Error("%s\n", e.what());
00230     }
00231 }
00232 
00233 void SelectionObserverPython::setPreselection(const SelectionChanges& msg)
00234 {
00235     Base::PyGILStateLocker lock;
00236     try {
00237         if (this->inst.hasAttr(std::string("setPreselection"))) {
00238             Py::Callable method(this->inst.getAttr(std::string("setPreselection")));
00239             Py::Tuple args(3);
00240             args.setItem(0, Py::String(msg.pDocName ? msg.pDocName : ""));
00241             args.setItem(1, Py::String(msg.pObjectName ? msg.pObjectName : ""));
00242             args.setItem(2, Py::String(msg.pSubName ? msg.pSubName : ""));
00243             method.apply(args);
00244         }
00245     }
00246     catch (Py::Exception&) {
00247         Base::PyException e; // extract the Python error text
00248         Base::Console().Error("%s\n", e.what());
00249     }
00250 }
00251 
00252 void SelectionObserverPython::removePreselection(const SelectionChanges& msg)
00253 {
00254     Base::PyGILStateLocker lock;
00255     try {
00256         if (this->inst.hasAttr(std::string("removePreselection"))) {
00257             Py::Callable method(this->inst.getAttr(std::string("removePreselection")));
00258             Py::Tuple args(3);
00259             args.setItem(0, Py::String(msg.pDocName ? msg.pDocName : ""));
00260             args.setItem(1, Py::String(msg.pObjectName ? msg.pObjectName : ""));
00261             args.setItem(2, Py::String(msg.pSubName ? msg.pSubName : ""));
00262             method.apply(args);
00263         }
00264     }
00265     catch (Py::Exception&) {
00266         Base::PyException e; // extract the Python error text
00267         Base::Console().Error("%s\n", e.what());
00268     }
00269 }
00270 
00271 // -------------------------------------------
00272 
00273 bool SelectionSingleton::hasSelection() const
00274 {
00275     return !_SelList.empty();
00276 }
00277 
00278 std::vector<SelectionSingleton::SelObj> SelectionSingleton::getCompleteSelection() const
00279 {
00280     std::vector<SelObj> temp;
00281     SelObj tempSelObj;
00282 
00283     for(std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) {
00284         tempSelObj.DocName  = It->DocName.c_str();
00285         tempSelObj.FeatName = It->FeatName.c_str();
00286         tempSelObj.SubName  = It->SubName.c_str();
00287         tempSelObj.TypeName = It->TypeName.c_str();
00288         tempSelObj.pObject  = It->pObject;
00289         tempSelObj.pDoc     = It->pDoc;
00290         temp.push_back(tempSelObj);
00291     }
00292 
00293     return temp;
00294 }
00295 
00296 std::vector<SelectionSingleton::SelObj> SelectionSingleton::getSelection(const char* pDocName) const
00297 {
00298     std::vector<SelObj> temp;
00299     SelObj tempSelObj;
00300 
00301     App::Document *pcDoc;
00302     pcDoc = getDocument(pDocName);
00303 
00304     if (!pcDoc)
00305         return temp;
00306 
00307     for(std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) {
00308         if (It->pDoc == pcDoc) {
00309             tempSelObj.DocName  = It->DocName.c_str();
00310             tempSelObj.FeatName = It->FeatName.c_str();
00311             tempSelObj.SubName  = It->SubName.c_str();
00312             tempSelObj.TypeName = It->TypeName.c_str();
00313             tempSelObj.pObject  = It->pObject;
00314             tempSelObj.pDoc     = It->pDoc;
00315             tempSelObj.x        = It->x;
00316             tempSelObj.y        = It->y;
00317             tempSelObj.z        = It->z;
00318             temp.push_back(tempSelObj);
00319         }
00320     }
00321 
00322     return temp;
00323 }
00324 
00325 bool SelectionSingleton::hasSelection(const char* doc) const
00326 {
00327     App::Document *pcDoc;
00328     pcDoc = getDocument(doc);
00329     if (!pcDoc)
00330         return false;
00331     for(std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) {
00332         if (It->pDoc == pcDoc) {
00333             return true;
00334         }
00335     }
00336 
00337     return false;
00338 }
00339 
00340 //std::vector<SelectionObject> SelectionSingleton::getSelectionEx(const char* pDocName) const
00341 //{
00342 //    return getSelectionEx(pDocName,App::DocumentObject::getClassTypeId());
00343 //}
00344 //
00345 //std::vector<SelectionObject> SelectionSingleton::getSelectionEx(const char* pDocName,const char* typeName) const
00346 //{
00347 //    // search the type
00348 //    Base::Type typeId;
00349 //    if(typeName)
00350 //        typeId = Base::Type::fromName(typeName);
00351 //    else
00352 //        typeId = App::DocumentObject::getClassTypeId();
00353 //    return getSelectionEx(pDocName,typeId);
00354 //}
00355 std::vector<SelectionObject> SelectionSingleton::getSelectionEx(const char* pDocName,Base::Type typeId) const
00356 {
00357     std::vector<SelectionObject> temp;
00358     
00359     std::map<App::DocumentObject*,SelectionObject> SortMap;
00360 
00361     // check the type
00362     if (typeId == Base::Type::badType()) 
00363         return temp;
00364 
00365     App::Document *pcDoc;
00366     string DocName;
00367 
00368     pcDoc = getDocument(pDocName);
00369 
00370     if (!pcDoc)
00371         return temp;
00372 
00373     for (std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) {
00374         if (It->pDoc == pcDoc) {
00375             // right type?
00376             if(It->pObject->getTypeId().isDerivedFrom(typeId)){
00377                 // if the object has already an entry
00378                 if (SortMap.find(It->pObject) != SortMap.end()){
00379                     // only add sub-element
00380                     SortMap[It->pObject].SubNames.push_back(It->SubName);
00381                     SortMap[It->pObject].SelPoses.push_back(Base::Vector3d(It->x,It->y,It->z));
00382                 }
00383                 else{
00384                     // create a new entry
00385                     SelectionObject tempSelObj;
00386                     tempSelObj.DocName  = It->DocName;
00387                     tempSelObj.FeatName = It->FeatName;
00388                     tempSelObj.SubNames.push_back(It->SubName);
00389                     tempSelObj.TypeName = It->TypeName.c_str();
00390                     tempSelObj.SelPoses.push_back(Base::Vector3d(It->x,It->y,It->z));
00391                     SortMap.insert(std::pair<App::DocumentObject*,SelectionObject>(It->pObject,tempSelObj));
00392                 }
00393             }
00394         }
00395     }
00396     for (std::map<App::DocumentObject*,SelectionObject>::const_iterator It = SortMap.begin();It != SortMap.end();++It) 
00397         temp.push_back(It->second);
00398 
00399     return temp;
00400 }
00401 
00402 vector<App::DocumentObject*> SelectionSingleton::getObjectsOfType(const Base::Type& typeId, const char* pDocName) const
00403 {
00404     std::vector<App::DocumentObject*> temp;
00405     App::Document *pcDoc;
00406 
00407     pcDoc = getDocument(pDocName);
00408 
00409     if (!pcDoc)
00410         return temp;
00411 
00412     for (std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) {
00413         if (It->pDoc == pcDoc && It->pObject && It->pObject->getTypeId().isDerivedFrom(typeId)) {
00414             temp.push_back(It->pObject);
00415         }
00416     }
00417 
00418     return temp;
00419 }
00420 
00421 std::vector<App::DocumentObject*> SelectionSingleton::getObjectsOfType(const char* typeName, const char* pDocName) const
00422 {
00423     Base::Type typeId = Base::Type::fromName(typeName);
00424     if (typeId == Base::Type::badType())
00425         return std::vector<App::DocumentObject*>();
00426     return getObjectsOfType(typeId, pDocName);
00427 }
00428 
00429 unsigned int SelectionSingleton::countObjectsOfType(const Base::Type& typeId, const char* pDocName) const
00430 {
00431     unsigned int iNbr=0;
00432     App::Document *pcDoc;
00433 
00434     pcDoc = getDocument(pDocName);
00435 
00436     if (!pcDoc)
00437         return 0;
00438 
00439     for (std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) {
00440         if (It->pDoc == pcDoc && It->pObject && It->pObject->getTypeId().isDerivedFrom(typeId)) {
00441             iNbr++;
00442         }
00443     }
00444 
00445     return iNbr;
00446 }
00447 
00448 unsigned int SelectionSingleton::countObjectsOfType(const char* typeName, const char* pDocName) const
00449 {
00450     Base::Type typeId = Base::Type::fromName(typeName);
00451     if (typeId == Base::Type::badType())
00452         return 0;
00453     return countObjectsOfType(typeId, pDocName);
00454 }
00455 
00456 bool SelectionSingleton::setPreselect(const char* pDocName, const char* pObjectName, const char* pSubName, float x, float y, float z)
00457 {
00458     static char buf[513];
00459 
00460     if (DocName != "")
00461         rmvPreselect();
00462 
00463     if(ActiveGate)
00464     {
00465         App::Document* pDoc = getDocument(pDocName);
00466 
00467         if (pDoc) {
00468             if(pObjectName){
00469                 App::DocumentObject* pObject = pDoc->getObject(pObjectName);
00470                 if(! ActiveGate->allow(pDoc,pObject,pSubName)){
00471                     snprintf(buf,512,"Not allowed: %s.%s.%s ",pDocName
00472                                                        ,pObjectName
00473                                                        ,pSubName
00474                                                        );
00475 
00476                     if (getMainWindow()){
00477                         getMainWindow()->showMessage(QString::fromAscii(buf),3000);
00478                         Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
00479                         if (mdi && mdi->isDerivedFrom(View3DInventor::getClassTypeId())) {
00480                             static_cast<View3DInventor*>(mdi)->setCursor(Qt::ForbiddenCursor);
00481                         }
00482                     }
00483                     return false;
00484                 }
00485 
00486             }else
00487                 return ActiveGate->allow(pDoc,0,0);
00488         }else
00489             return false;
00490 
00491     }
00492 
00493     DocName = pDocName;
00494     FeatName= pObjectName;
00495     SubName = pSubName;
00496     hx = x;
00497     hy = y;
00498     hz = z;
00499 
00500     // set up the change object
00501     SelectionChanges Chng;
00502     Chng.pDocName  = DocName.c_str();
00503     Chng.pObjectName = FeatName.c_str();
00504     Chng.pSubName  = SubName.c_str();
00505     Chng.x = x;
00506     Chng.y = y;
00507     Chng.z = z;
00508     Chng.Type = SelectionChanges::SetPreselect;
00509 
00510     // set the current preselection
00511     CurrentPreselection = Chng;
00512 
00513     snprintf(buf,512,"Preselected: %s.%s.%s (%f,%f,%f)",Chng.pDocName
00514                                                        ,Chng.pObjectName
00515                                                        ,Chng.pSubName
00516                                                        ,x,y,z);
00517 
00518     if (getMainWindow()){
00519         getMainWindow()->showMessage(QString::fromAscii(buf),3000);
00520         Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
00521         if (mdi && mdi->isDerivedFrom(View3DInventor::getClassTypeId())) {
00522             static_cast<View3DInventor*>(mdi)->setCursor(Qt::ArrowCursor);
00523         }
00524     }
00525 
00526     Notify(Chng);
00527     signalSelectionChanged(Chng);
00528 
00529     //Base::Console().Log("Sel : Add preselect %s \n",pObjectName);
00530 
00531     // allows the preselection
00532     return true;
00533 }
00534 
00535 void SelectionSingleton::setPreselectCoord( float x, float y, float z)
00536 {
00537     static char buf[513];
00538 
00539     // if nothing is in preselect ignore
00540     if(!CurrentPreselection.pObjectName) return;
00541 
00542     CurrentPreselection.x = x;
00543     CurrentPreselection.y = y;
00544     CurrentPreselection.z = z;
00545 
00546     snprintf(buf,512,"Preselected: %s.%s.%s (%f,%f,%f)",CurrentPreselection.pDocName
00547                                                        ,CurrentPreselection.pObjectName
00548                                                        ,CurrentPreselection.pSubName
00549                                                        ,x,y,z);
00550 
00551     if (getMainWindow())
00552         getMainWindow()->showMessage(QString::fromAscii(buf),3000);
00553 }
00554 
00555 void SelectionSingleton::rmvPreselect()
00556 {
00557     if (DocName == "")
00558         return;
00559 
00560     SelectionChanges Chng;
00561     Chng.pDocName  = DocName.c_str();
00562     Chng.pObjectName = FeatName.c_str();
00563     Chng.pSubName  = SubName.c_str();
00564     Chng.Type = SelectionChanges::RmvPreselect;
00565 
00566     // reset the current preselection
00567     CurrentPreselection.pDocName =0;
00568     CurrentPreselection.pObjectName = 0;
00569     CurrentPreselection.pSubName = 0;
00570     CurrentPreselection.x = 0.0;
00571     CurrentPreselection.y = 0.0;
00572     CurrentPreselection.z = 0.0;
00573 
00574     // notify observing objects
00575     Notify(Chng);
00576     signalSelectionChanged(Chng);
00577 
00578     DocName = "";
00579     FeatName= "";
00580     SubName = "";
00581     hx = 0;
00582     hy = 0;
00583     hz = 0;
00584 
00585     if (getMainWindow()){
00586         Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
00587         if (mdi && mdi->isDerivedFrom(View3DInventor::getClassTypeId())) {
00588             static_cast<View3DInventor*>(mdi)->setCursor(Qt::ArrowCursor);
00589         }
00590     }
00591 
00592     //Base::Console().Log("Sel : Rmv preselect \n");
00593 }
00594 
00595 const SelectionChanges &SelectionSingleton::getPreselection(void) const
00596 {
00597     return CurrentPreselection;
00598 }
00599 
00600 // add a SelectionGate to control what is selectable
00601 void SelectionSingleton::addSelectionGate(Gui::SelectionGate *gate)
00602 {
00603     if(ActiveGate)
00604         rmvSelectionGate();
00605     
00606     ActiveGate = gate;
00607 
00608 }
00609 
00610 // remove the active SelectionGate
00611 void SelectionSingleton::rmvSelectionGate(void)
00612 {
00613     if (ActiveGate)
00614         delete ActiveGate;
00615     ActiveGate=0;
00616 }
00617 
00618 
00619 App::Document* SelectionSingleton::getDocument(const char* pDocName) const
00620 {
00621     if (pDocName)
00622         return App::GetApplication().getDocument(pDocName);
00623     else
00624         return App::GetApplication().getActiveDocument();
00625 }
00626 
00627 bool SelectionSingleton::addSelection(const char* pDocName, const char* pObjectName, const char* pSubName, float x, float y, float z)
00628 {
00629     // already in ?
00630     if (isSelected(pDocName, pObjectName, pSubName))
00631         return true;
00632 
00633      _SelObj temp;
00634 
00635     temp.pDoc = getDocument(pDocName);
00636 
00637     if (temp.pDoc) {
00638         if(pObjectName)
00639             temp.pObject = temp.pDoc->getObject(pObjectName);
00640         else
00641             temp.pObject = 0;
00642         
00643         // check for a Selection Gate
00644         if(ActiveGate)
00645         {
00646             if(! ActiveGate->allow(temp.pDoc,temp.pObject,pSubName)){
00647                 if (getMainWindow()){
00648                     getMainWindow()->showMessage(QString::fromAscii("Selection not allowed by filter"),5000);
00649                     Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
00650                     if (mdi && mdi->isDerivedFrom(View3DInventor::getClassTypeId())) {
00651                         static_cast<View3DInventor*>(mdi)->setCursor(Qt::ForbiddenCursor);
00652                     }
00653                 }
00654                 QApplication::beep();
00655                 return false;
00656             }
00657         }
00658 
00659         temp.DocName  = pDocName;
00660         temp.FeatName = pObjectName ? pObjectName : "";
00661         temp.SubName  = pSubName ? pSubName : "";
00662         temp.x        = x;
00663         temp.y        = y;
00664         temp.z        = z;
00665 
00666         if (temp.pObject)
00667             temp.TypeName = temp.pObject->getTypeId().getName();
00668 
00669         _SelList.push_back(temp);
00670 
00671         SelectionChanges Chng;
00672 
00673         Chng.pDocName  = pDocName;
00674         Chng.pObjectName = pObjectName ? pObjectName : "";
00675         Chng.pSubName  = pSubName ? pSubName : "";
00676         Chng.x         = x;
00677         Chng.y         = y;
00678         Chng.z         = z;
00679         Chng.Type      = SelectionChanges::AddSelection;
00680 
00681 
00682         Notify(Chng);
00683         signalSelectionChanged(Chng);
00684 
00685         Base::Console().Log("Sel : Add Selection \"%s.%s.%s(%f,%f,%f)\"\n",pDocName,pObjectName,pSubName,x,y,z);
00686 
00687         // allow selection
00688         return true;
00689     }
00690     else { // neither an existing nor active document available 
00691         //assert(0);
00692         // this can often happen when importing .iv files
00693         Base::Console().Error("Cannot add to selection: no document '%s' found.\n", pDocName);
00694         return false;
00695     }
00696 }
00697 
00698 void SelectionSingleton::rmvSelection(const char* pDocName, const char* pObjectName, const char* pSubName)
00699 {
00700     std::vector<SelectionChanges> rmvList;
00701 
00702     for (std::list<_SelObj>::iterator It = _SelList.begin();It != _SelList.end();) {
00703         if ((It->DocName == pDocName && !pObjectName) ||
00704             (It->DocName == pDocName && pObjectName && It->FeatName == pObjectName && !pSubName) ||
00705             (It->DocName == pDocName && pObjectName && It->FeatName == pObjectName && pSubName && It->SubName == pSubName))
00706         {
00707             // save in tmp. string vars
00708             std::string tmpDocName = It->DocName;
00709             std::string tmpFeaName = It->FeatName;
00710             std::string tmpSubName = It->SubName;
00711 
00712             // destroy the _SelObj item
00713             It = _SelList.erase(It);
00714 
00715             SelectionChanges Chng;
00716             Chng.pDocName  = tmpDocName.c_str();
00717             Chng.pObjectName = tmpFeaName.c_str();
00718             Chng.pSubName  = tmpSubName.c_str();
00719             Chng.Type      = SelectionChanges::RmvSelection;
00720 
00721             Notify(Chng);
00722             signalSelectionChanged(Chng);
00723       
00724             rmvList.push_back(Chng);
00725             Base::Console().Log("Sel : Rmv Selection \"%s.%s.%s\"\n",pDocName,pObjectName,pSubName);
00726         }
00727         else {
00728             ++It;
00729         }
00730     }
00731 }
00732 
00733 void SelectionSingleton::setSelection(const char* pDocName, const std::vector<App::DocumentObject*>& sel)
00734 {
00735     App::Document *pcDoc;
00736     pcDoc = getDocument(pDocName);
00737     if (!pcDoc)
00738         return;
00739 
00740     std::set<App::DocumentObject*> cur_sel, new_sel;
00741     new_sel.insert(sel.begin(), sel.end());
00742 
00743     // Make sure to keep the order of the currently selected objects
00744     std::list<_SelObj> temp;
00745     for (std::list<_SelObj>::const_iterator it = _SelList.begin(); it != _SelList.end(); ++it) {
00746         if (it->pDoc != pcDoc)
00747             temp.push_back(*it);
00748         else {
00749             cur_sel.insert(it->pObject);
00750             if (new_sel.find(it->pObject) != new_sel.end())
00751                 temp.push_back(*it);
00752         }
00753     }
00754 
00755     // Get the objects we must add to the selection
00756     std::vector<App::DocumentObject*> diff_new_cur;
00757     std::back_insert_iterator< std::vector<App::DocumentObject*> > biit(diff_new_cur);
00758     std::set_difference(new_sel.begin(), new_sel.end(), cur_sel.begin(), cur_sel.end(), biit);
00759 
00760     _SelObj obj;
00761     for (std::vector<App::DocumentObject*>::const_iterator it = diff_new_cur.begin(); it != diff_new_cur.end(); ++it) {
00762         obj.pDoc = pcDoc;
00763         obj.pObject = *it;
00764         obj.DocName = pDocName;
00765         obj.FeatName = (*it)->getNameInDocument();
00766         obj.SubName = "";
00767         obj.TypeName = (*it)->getTypeId().getName();
00768         obj.x = 0.0f;
00769         obj.y = 0.0f;
00770         obj.z = 0.0f;
00771         temp.push_back(obj);
00772     }
00773 
00774     if (cur_sel == new_sel) // nothing has changed
00775         return;
00776 
00777     _SelList = temp;
00778 
00779     SelectionChanges Chng;
00780     Chng.Type = SelectionChanges::SetSelection;
00781     Chng.pDocName = pDocName;
00782     Chng.pObjectName = "";
00783     Chng.pSubName = "";
00784 
00785     Notify(Chng);
00786     signalSelectionChanged(Chng);
00787 }
00788 
00789 void SelectionSingleton::clearSelection(const char* pDocName)
00790 {
00791     App::Document* pDoc;
00792     pDoc = getDocument(pDocName);
00793 
00794     // the document 'pDocName' has already been removed
00795     if (!pDoc && !pDocName) {
00796         clearCompleteSelection();
00797     }
00798     else {
00799         std::string docName;
00800         if (pDocName)
00801             docName = pDocName;
00802         else
00803             docName = pDoc->getName(); // active document
00804         std::list<_SelObj> selList;
00805         for (std::list<_SelObj>::iterator it = _SelList.begin(); it != _SelList.end(); ++it) {
00806             if (it->DocName != docName)
00807                 selList.push_back(*it);
00808         }
00809 
00810         _SelList = selList;
00811 
00812         SelectionChanges Chng;
00813         Chng.Type = SelectionChanges::ClrSelection;
00814         Chng.pDocName = docName.c_str();
00815         Chng.pObjectName = "";
00816         Chng.pSubName = "";
00817 
00818         Notify(Chng);
00819         signalSelectionChanged(Chng);
00820 
00821         Base::Console().Log("Sel : Clear selection\n");
00822     }
00823 }
00824 
00825 void SelectionSingleton::clearCompleteSelection()
00826 {
00827     _SelList.clear();
00828 
00829     SelectionChanges Chng;
00830     Chng.Type = SelectionChanges::ClrSelection;
00831     Chng.pDocName = "";
00832     Chng.pObjectName = "";
00833     Chng.pSubName = "";
00834 
00835 
00836     Notify(Chng);
00837     signalSelectionChanged(Chng);
00838 
00839     Base::Console().Log("Sel : Clear selection\n");
00840 }
00841 
00842 bool SelectionSingleton::isSelected(const char* pDocName, const char* pObjectName, const char* pSubName) const
00843 {
00844     const char* tmpDocName = pDocName ? pDocName : "";
00845     const char* tmpFeaName = pObjectName ? pObjectName : "";
00846     const char* tmpSubName = pSubName ? pSubName : "";
00847     for (std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It)
00848         if (It->DocName == tmpDocName && It->FeatName == tmpFeaName && It->SubName == tmpSubName)
00849             return true;
00850     return false;
00851 }
00852 
00853 bool SelectionSingleton::isSelected(App::DocumentObject* obj, const char* pSubName) const
00854 {
00855     if (!obj) return false;
00856 
00857     for(list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) {
00858         if (It->pObject == obj) {
00859             if (pSubName) {
00860                 if (It->SubName == pSubName)
00861                     return true;
00862             }
00863             else {
00864                 return true;
00865             }
00866         }
00867     }
00868 
00869     return false;
00870 }
00871 
00872 void SelectionSingleton::slotDeletedObject(const App::DocumentObject& Obj)
00873 {
00874     // remove also from the selection, if selected
00875     Selection().rmvSelection( Obj.getDocument()->getName(), Obj.getNameInDocument() );
00876 }
00877 
00878 void SelectionSingleton::slotRenamedObject(const App::DocumentObject& Obj)
00879 {
00880     // compare internals with the document and change them if needed
00881     App::Document* pDoc = Obj.getDocument();
00882     for (std::list<_SelObj>::iterator it = _SelList.begin(); it != _SelList.end(); ++it) {
00883         if (it->pDoc == pDoc) {
00884             it->DocName = pDoc->getName();
00885         }
00886     }
00887 }
00888 
00889 
00890 //**************************************************************************
00891 // Construction/Destruction
00892 
00897 SelectionSingleton::SelectionSingleton()
00898 {
00899     ActiveGate = 0;
00900     App::GetApplication().signalDeletedObject.connect(boost::bind(&Gui::SelectionSingleton::slotDeletedObject, this, _1));
00901     App::GetApplication().signalRenamedObject.connect(boost::bind(&Gui::SelectionSingleton::slotRenamedObject, this, _1));
00902     CurrentPreselection.pDocName = 0;
00903     CurrentPreselection.pObjectName = 0;
00904     CurrentPreselection.pSubName = 0;
00905 
00906 }
00907 
00912 SelectionSingleton::~SelectionSingleton()
00913 {
00914 }
00915 
00916 
00917 SelectionSingleton* SelectionSingleton::_pcSingleton = NULL;
00918 
00919 SelectionSingleton& SelectionSingleton::instance(void)
00920 {
00921     if (_pcSingleton == NULL)
00922         _pcSingleton = new SelectionSingleton;
00923     return *_pcSingleton;
00924 }
00925 
00926 void SelectionSingleton::destruct (void)
00927 {
00928     if (_pcSingleton != NULL)
00929         delete _pcSingleton;
00930     _pcSingleton = 0;
00931 }
00932 /*
00933 void SelectionSingleton::addObject(App::DocumentObject *f)
00934 {
00935   _ObjectSet.insert(f);
00936 
00937 }
00938 
00939 void SelectionSingleton::removeObject(App::DocumentObject *f)
00940 {
00941   _ObjectSet.erase(f);
00942 
00943 
00944 }
00945 */
00946 
00947 
00948 //**************************************************************************
00949 // Python stuff
00950 
00951 // SelectionSingleton Methods  // Methods structure
00952 PyMethodDef SelectionSingleton::Methods[] = {
00953     {"addSelection",         (PyCFunction) SelectionSingleton::sAddSelection, 1, 
00954      "addSelection(object) -- Add an object to the selection"},
00955     {"removeSelection",      (PyCFunction) SelectionSingleton::sRemoveSelection, 1,
00956      "removeSelection(object) -- Remove an object from the selection"},
00957     {"clearSelection"  ,     (PyCFunction) SelectionSingleton::sClearSelection, 1,
00958      "clearSelection([string]) -- Clear the selection\n"
00959      "Clear the selection to the given document name. If no document is\n"
00960      "given the complete selection is cleared."},
00961     {"isSelected",           (PyCFunction) SelectionSingleton::sIsSelected, 1,
00962      "isSelected(object) -- Check if a given object is selected"},
00963     {"getSelection",         (PyCFunction) SelectionSingleton::sGetSelection, 1,
00964      "getSelection([string]) -- Return a list of selected objets\n"
00965      "Return a list of selected objects for a given document name. If no\n"
00966      "document is given the complete selection is returned."},
00967     {"getSelectionEx",         (PyCFunction) SelectionSingleton::sGetSelectionEx, 1,
00968      "getSelectionEx([string]) -- Return a list of SelectionObjects\n"
00969      "Return a list of SelectionObjects for a given document name. If no\n"
00970      "document is given the selection of the active document is returned.\n"
00971      "The SelectionObjects contain a variety of information about the selection,\n"
00972      "e.g. sub-element names."},
00973     {"addObserver",         (PyCFunction) SelectionSingleton::sAddSelObserver, 1,
00974      "addObserver(Object) -- Install an observer\n"},
00975     {"removeObserver",      (PyCFunction) SelectionSingleton::sRemSelObserver, 1,
00976      "removeObserver(Object) -- Uninstall an observer\n"},
00977     {"addSelectionGate",      (PyCFunction) SelectionSingleton::saddSelectionGate, 1,
00978     "addSelectionGate(String) -- activate the selection gate.\n"
00979     "The selection gate will prohibit all selections which do not match the\n"
00980     "the given selection filter string. Examples strings are:\n"
00981     "'SELECT Part::Feature SUB Edge',\n"
00982     "'SELECT Robot::RobotObject'\n"},
00983     {"removeSelectionGate",      (PyCFunction) SelectionSingleton::sremoveSelectionGate, 1,
00984      "removeSelectionGate() -- remove the active slection gate\n"},
00985     {NULL, NULL, 0, NULL}  /* Sentinel */
00986 };
00987 
00988 PyObject *SelectionSingleton::sAddSelection(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
00989 {
00990     PyObject *object;
00991     char* subname=0;
00992     float x=0,y=0,z=0;
00993     if (!PyArg_ParseTuple(args, "O!|sfff", &(App::DocumentObjectPy::Type),&object,&subname,&x,&y,&z))
00994         return NULL;                             // NULL triggers exception 
00995 
00996     App::DocumentObjectPy* docObjPy = static_cast<App::DocumentObjectPy*>(object);
00997     App::DocumentObject* docObj = docObjPy->getDocumentObjectPtr();
00998     if (!docObj || !docObj->getNameInDocument()) {
00999         PyErr_SetString(PyExc_Exception, "Cannot check invalid object");
01000         return NULL;
01001     }
01002 
01003     Selection().addSelection(docObj->getDocument()->getName(),
01004                              docObj->getNameInDocument(),
01005                              subname,x,y,z);
01006 
01007     Py_Return;
01008 }
01009 
01010 PyObject *SelectionSingleton::sRemoveSelection(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
01011 {
01012     PyObject *object;
01013     char* subname=0;
01014     if (!PyArg_ParseTuple(args, "O!|s", &(App::DocumentObjectPy::Type),&object,&subname))
01015         return NULL;                             // NULL triggers exception 
01016 
01017     App::DocumentObjectPy* docObjPy = static_cast<App::DocumentObjectPy*>(object);
01018     App::DocumentObject* docObj = docObjPy->getDocumentObjectPtr();
01019     if (!docObj || !docObj->getNameInDocument()) {
01020         PyErr_SetString(PyExc_Exception, "Cannot check invalid object");
01021         return NULL;
01022     }
01023 
01024     Selection().rmvSelection(docObj->getDocument()->getName(),
01025                              docObj->getNameInDocument(),
01026                              subname);
01027 
01028     Py_Return;
01029 }
01030 
01031 PyObject *SelectionSingleton::sClearSelection(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
01032 {
01033     char *documentName=0;
01034     if (!PyArg_ParseTuple(args, "|s", &documentName))     // convert args: Python->C 
01035         return NULL;                             // NULL triggers exception
01036     documentName ? Selection().clearSelection(documentName) : Selection().clearCompleteSelection();
01037     Py_Return;
01038 }
01039 
01040 PyObject *SelectionSingleton::sIsSelected(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
01041 {
01042     PyObject *object;
01043     char* subname=0;
01044     if (!PyArg_ParseTuple(args, "O!|s", &(App::DocumentObjectPy::Type), &object, &subname))
01045         return NULL;                             // NULL triggers exception 
01046 
01047     App::DocumentObjectPy* docObj = static_cast<App::DocumentObjectPy*>(object);
01048     bool ok = Selection().isSelected(docObj->getDocumentObjectPtr(), subname);
01049     return Py_BuildValue("O", (ok ? Py_True : Py_False));
01050 }
01051 
01052 PyObject *SelectionSingleton::sGetSelection(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
01053 {
01054     char *documentName=0;
01055     if (!PyArg_ParseTuple(args, "|s", &documentName))     // convert args: Python->C 
01056         return NULL;                             // NULL triggers exception
01057 
01058     std::vector<SelectionSingleton::SelObj> sel;
01059     if (documentName)
01060         sel = Selection().getSelection(documentName);
01061     else
01062         sel = Selection().getCompleteSelection();
01063 
01064     try {
01065         Py::List list;
01066         for (std::vector<SelectionSingleton::SelObj>::iterator it = sel.begin(); it != sel.end(); ++it) {
01067             list.append(Py::asObject(it->pObject->getPyObject()));
01068         }
01069         return Py::new_reference_to(list);
01070     }
01071     catch (Py::Exception&) {
01072         return 0;
01073     }
01074 }
01075 
01076 PyObject *SelectionSingleton::sGetSelectionEx(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
01077 {
01078     char *documentName=0;
01079     if (!PyArg_ParseTuple(args, "|s", &documentName))     // convert args: Python->C 
01080         return NULL;                             // NULL triggers exception
01081 
01082     std::vector<SelectionObject> sel;
01083     sel = Selection().getSelectionEx(documentName);
01084 
01085     try {
01086         Py::List list;
01087         for (std::vector<SelectionObject>::iterator it = sel.begin(); it != sel.end(); ++it) {
01088             list.append(Py::asObject(it->getPyObject()));
01089         }
01090         return Py::new_reference_to(list);
01091     }
01092     catch (Py::Exception&) {
01093         return 0;
01094     }
01095 }
01096 
01097 PyObject *SelectionSingleton::sAddSelObserver(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
01098 {
01099     PyObject* o;
01100     if (!PyArg_ParseTuple(args, "O",&o))
01101         return NULL;
01102     PY_TRY {
01103         SelectionObserverPython::addObserver(Py::Object(o));
01104         Py_Return;
01105     } PY_CATCH;
01106 }
01107 
01108 PyObject *SelectionSingleton::sRemSelObserver(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
01109 {
01110     PyObject* o;
01111     if (!PyArg_ParseTuple(args, "O",&o))
01112         return NULL;
01113     PY_TRY {
01114         SelectionObserverPython::removeObserver(Py::Object(o));
01115         Py_Return;
01116     } PY_CATCH;
01117 }
01118 
01119 PyObject *SelectionSingleton::saddSelectionGate(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
01120 {
01121     char* filter;
01122     if (!PyArg_ParseTuple(args, "s",&filter))
01123         return NULL;                             // NULL triggers exception 
01124 
01125     PY_TRY {
01126         Selection().addSelectionGate(new SelectionFilterGate(filter));
01127     } PY_CATCH;
01128 
01129     Py_Return;
01130 }
01131 
01132 PyObject *SelectionSingleton::sremoveSelectionGate(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
01133 {
01134     if (!PyArg_ParseTuple(args, ""))
01135         return NULL;                             // NULL triggers exception 
01136 
01137     PY_TRY {
01138         Selection().rmvSelectionGate();
01139     } PY_CATCH;
01140 
01141     Py_Return;
01142 }

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