Gui/Document.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2004 Jürgen 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 <qapplication.h>
00028 # include <qdir.h>
00029 # include <qfileinfo.h>
00030 # include <qmessagebox.h>
00031 # include <qstatusbar.h>
00032 # include <boost/signals.hpp>
00033 # include <boost/bind.hpp>
00034 #endif
00035 
00036 #include <Base/Console.h>
00037 #include <Base/Exception.h>
00038 #include <Base/Matrix.h>
00039 #include <Base/Reader.h>
00040 #include <Base/Writer.h>
00041 
00042 #include <App/Document.h>
00043 #include <App/DocumentObject.h>
00044 
00045 #include "Application.h"
00046 #include "MainWindow.h"
00047 #include "Tree.h"
00048 #include "Document.h"
00049 #include "DocumentPy.h"
00050 #include "Command.h"
00051 #include "Control.h"
00052 #include "FileDialog.h"
00053 #include "View3DInventor.h"
00054 #include "View3DInventorViewer.h"
00055 #include "BitmapFactory.h"
00056 #include "ViewProviderDocumentObject.h"
00057 #include "Selection.h"
00058 #include "SoFCSelection.h"
00059 #include "WaitCursor.h"
00060 #include "Thumbnail.h"
00061 
00062 using namespace Gui;
00063 
00064 namespace Gui {
00065 
00066 // Pimpl class
00067 struct DocumentP
00068 {
00069     Thumbnail thumb;
00070     int        _iWinCount;
00071     int        _iDocId;
00072     bool       _isClosing;
00073     bool       _isModified;
00074     ViewProvider*   _pcInEdit;
00075     Application*    _pcAppWnd;
00076     // the doc/Document
00077     App::Document*  _pcDocument;
00079     std::list<Gui::BaseView*> baseViews;
00081     std::list<Gui::BaseView*> passiveViews;
00082     std::map<const App::DocumentObject*,ViewProviderDocumentObject*> _ViewProviderMap;
00083     std::map<std::string,ViewProvider*> _ViewProviderMapAnnotation;
00084 
00085     typedef boost::signals::connection Connection;
00086     Connection connectNewObject;
00087     Connection connectDelObject;
00088     Connection connectCngObject;
00089     Connection connectRenObject;
00090     Connection connectActObject;
00091     Connection connectSaveDocument;
00092     Connection connectRestDocument;
00093     Connection connectLoadDocument;
00094 };
00095 
00096 } // namespace Gui
00097 
00098 /* TRANSLATOR Gui::Document */
00099 
00101 
00102 int Document::_iDocCount = 0;
00103 
00104 Document::Document(App::Document* pcDocument,Application * app)
00105 {
00106     d = new DocumentP;
00107     d->_iWinCount = 1;
00108     // new instance
00109     d->_iDocId = (++_iDocCount);
00110     d->_isClosing = false;
00111     d->_isModified = false;
00112     d->_pcAppWnd = app;
00113     d->_pcDocument = pcDocument;
00114     d->_pcInEdit = 0;
00115 
00116     // Setup the connections
00117     d->connectNewObject = pcDocument->signalNewObject.connect
00118         (boost::bind(&Gui::Document::slotNewObject, this, _1));
00119     d->connectDelObject = pcDocument->signalDeletedObject.connect
00120         (boost::bind(&Gui::Document::slotDeletedObject, this, _1));
00121     d->connectCngObject = pcDocument->signalChangedObject.connect
00122         (boost::bind(&Gui::Document::slotChangedObject, this, _1, _2));
00123     d->connectRenObject = pcDocument->signalRenamedObject.connect
00124         (boost::bind(&Gui::Document::slotRenamedObject, this, _1));
00125     d->connectActObject = pcDocument->signalActivatedObject.connect
00126         (boost::bind(&Gui::Document::slotActivatedObject, this, _1));
00127     d->connectSaveDocument = pcDocument->signalSaveDocument.connect
00128         (boost::bind(&Gui::Document::Save, this, _1));
00129     d->connectRestDocument = pcDocument->signalRestoreDocument.connect
00130         (boost::bind(&Gui::Document::Restore, this, _1));
00131     d->connectLoadDocument = App::GetApplication().signalRestoreDocument.connect
00132         (boost::bind(&Gui::Document::slotRestoredDocument, this, _1));
00133 
00134     // pointer to the python class
00135     // NOTE: As this Python object doesn't get returned to the interpreter we
00136     // mustn't increment it (Werner Jan-12-2006)
00137     _pcDocPy = new Gui::DocumentPy(this);
00138 
00139     if (App::GetApplication().GetParameterGroupByPath
00140         ("User parameter:BaseApp/Preferences/Document")->GetBool("UsingUndo",true)){
00141         d->_pcDocument->setUndoMode(1);
00142         // set the maximum stack size
00143         d->_pcDocument->setMaxUndoStackSize(App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document")->GetInt("MaxUndoSize",20));
00144     }
00145 }
00146 
00147 Document::~Document()
00148 {
00149     // disconnect everything to avoid to be double-deleted
00150     // in case an exception is raised somewhere
00151     d->connectNewObject.disconnect();
00152     d->connectDelObject.disconnect();
00153     d->connectCngObject.disconnect();
00154     d->connectRenObject.disconnect();
00155     d->connectActObject.disconnect();
00156     d->connectSaveDocument.disconnect();
00157     d->connectRestDocument.disconnect();
00158     d->connectLoadDocument.disconnect();
00159 
00160     // e.g. if document gets closed from within a Python command
00161     d->_isClosing = true;
00162     // calls Document::detachView() and alter the view list
00163     std::list<Gui::BaseView*> temp = d->baseViews;
00164     for(std::list<Gui::BaseView*>::iterator it=temp.begin();it!=temp.end();++it)
00165         (*it)->deleteSelf();
00166 
00167     std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::iterator jt;
00168     for (jt = d->_ViewProviderMap.begin();jt != d->_ViewProviderMap.end(); ++jt)
00169         delete jt->second;
00170     std::map<std::string,ViewProvider*>::iterator it2;
00171     for (it2 = d->_ViewProviderMapAnnotation.begin();it2 != d->_ViewProviderMapAnnotation.end(); ++it2)
00172         delete it2->second;
00173 
00174     // remove the reference from the object
00175     _pcDocPy->setInvalid();
00176     _pcDocPy->DecRef();
00177     delete d;
00178 }
00179 
00180 //*****************************************************************************************************
00181 // 3D viewer handling
00182 //*****************************************************************************************************
00183 
00184 bool Document::setEdit(Gui::ViewProvider* p, int ModNum)
00185 {
00186     if (d->_pcInEdit)
00187         resetEdit();
00188     View3DInventor *activeView = dynamic_cast<View3DInventor *>(getActiveView());
00189     if (activeView && activeView->getViewer()->setEditingViewProvider(p,ModNum)) {
00190         d->_pcInEdit = p;
00191         if (d->_pcInEdit->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) 
00192             signalInEdit(*(static_cast<ViewProviderDocumentObject*>(d->_pcInEdit)));
00193     }
00194     else
00195         return false;
00196     return true;
00197 }
00198 
00199 void Document::resetEdit(void)
00200 {
00201     std::list<Gui::BaseView*>::iterator it;
00202     if (d->_pcInEdit) {
00203         for (it = d->baseViews.begin();it != d->baseViews.end();++it) {
00204             View3DInventor *activeView = dynamic_cast<View3DInventor *>(*it);
00205             if (activeView)
00206                 activeView->getViewer()->resetEditingViewProvider();
00207         }
00208 
00209         if (d->_pcInEdit->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) 
00210             signalResetEdit(*(static_cast<ViewProviderDocumentObject*>(d->_pcInEdit)));
00211         d->_pcInEdit = 0;
00212     }
00213 }
00214 
00215 ViewProvider *Document::getInEdit(void) const
00216 {
00217     if (d->_pcInEdit) {
00218         // there is only one 3d view which is in edit mode
00219         View3DInventor *activeView = dynamic_cast<View3DInventor *>(getActiveView());
00220         if (activeView && activeView->getViewer()->isEditingViewProvider())
00221             return d->_pcInEdit;
00222     }
00223 
00224     return 0;
00225 }
00226 
00227 void Document::setAnnotationViewProvider(const char* name, ViewProvider *pcProvider)
00228 {
00229     std::list<Gui::BaseView*>::iterator vIt;
00230 
00231     // already in ?
00232     std::map<std::string,ViewProvider*>::iterator it = d->_ViewProviderMapAnnotation.find(name);
00233     if (it != d->_ViewProviderMapAnnotation.end())
00234         removeAnnotationViewProvider(name);
00235 
00236     // add 
00237     d->_ViewProviderMapAnnotation[name] = pcProvider;
00238 
00239     // cycling to all views of the document
00240     for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) {
00241         View3DInventor *activeView = dynamic_cast<View3DInventor *>(*vIt);
00242         if (activeView)
00243             activeView->getViewer()->addViewProvider(pcProvider);
00244     }
00245 }
00246 
00247 ViewProvider * Document::getAnnotationViewProvider(const char* name) const
00248 {
00249     std::map<std::string,ViewProvider*>::const_iterator it = d->_ViewProviderMapAnnotation.find(name);
00250     return ( (it != d->_ViewProviderMapAnnotation.end()) ? it->second : 0 );
00251 }
00252 
00253 void Document::removeAnnotationViewProvider(const char* name)
00254 {
00255     std::map<std::string,ViewProvider*>::iterator it = d->_ViewProviderMapAnnotation.find(name);
00256     std::list<Gui::BaseView*>::iterator vIt;
00257 
00258     // cycling to all views of the document
00259     for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) {
00260         View3DInventor *activeView = dynamic_cast<View3DInventor *>(*vIt);
00261         if (activeView)
00262             activeView->getViewer()->removeViewProvider(it->second);
00263     }
00264 
00265     delete it->second;
00266     d->_ViewProviderMapAnnotation.erase(it); 
00267 }
00268 
00269 
00270 ViewProvider* Document::getViewProvider(const App::DocumentObject* Feat) const
00271 {
00272     std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator
00273     it = d->_ViewProviderMap.find( Feat );
00274     return ( (it != d->_ViewProviderMap.end()) ? it->second : 0 );
00275 }
00276 
00277 std::vector<ViewProvider*> Document::getViewProvidersOfType(const Base::Type& typeId) const
00278 {
00279     std::vector<ViewProvider*> Objects;
00280     for (std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator it = 
00281          d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it ) {
00282         if (it->second->getTypeId().isDerivedFrom(typeId))
00283             Objects.push_back(it->second);
00284     }
00285     return Objects;
00286 }
00287 
00288 ViewProvider *Document::getViewProviderByName(const char* name) const
00289 {
00290     // first check on feature name
00291     App::DocumentObject *pcFeat = getDocument()->getObject(name);
00292 
00293     if (pcFeat)
00294     {
00295         std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator
00296         it = d->_ViewProviderMap.find( pcFeat );
00297 
00298         if (it != d->_ViewProviderMap.end())
00299             return it->second;
00300     } else {
00301         // then try annotation name
00302         std::map<std::string,ViewProvider*>::const_iterator it2 = d->_ViewProviderMapAnnotation.find( name );
00303 
00304         if (it2 != d->_ViewProviderMapAnnotation.end())
00305             return it2->second;
00306     }
00307 
00308     return 0;
00309 }
00310 
00311 bool Document::isShow(const char* name)
00312 {
00313     ViewProvider* pcProv = getViewProviderByName(name);
00314     return pcProv ? pcProv->isShow() : false;
00315 }
00316 
00318 void Document::setShow(const char* name)
00319 {
00320     ViewProvider* pcProv = getViewProviderByName(name);
00321 
00322     if (pcProv && pcProv->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
00323         ((ViewProviderDocumentObject*)pcProv)->Visibility.setValue(true);
00324     }
00325 }
00326 
00328 void Document::setHide(const char* name)
00329 {
00330     ViewProvider* pcProv = getViewProviderByName(name);
00331 
00332     if (pcProv && pcProv->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
00333         ((ViewProviderDocumentObject*)pcProv)->Visibility.setValue(false);
00334     }
00335 }
00336 
00338 void Document::setPos(const char* name, const Base::Matrix4D& rclMtrx)
00339 {
00340     ViewProvider* pcProv = getViewProviderByName(name);
00341     if (pcProv)
00342         pcProv->setTransformation(rclMtrx);
00343 
00344 }
00345 
00346 //*****************************************************************************************************
00347 // Document
00348 //*****************************************************************************************************
00349 void Document::slotNewObject(const App::DocumentObject& Obj)
00350 {
00351     //Base::Console().Log("Document::slotNewObject() called\n");
00352     std::string cName = Obj.getViewProviderName();
00353     if (cName.empty()) {
00354         // handle document object with no view provider specified
00355         Base::Console().Log("%s has no view provider specified\n", Obj.getTypeId().getName());
00356         return;
00357     }
00358   
00359     setModified(true);
00360     Base::BaseClass* base = static_cast<Base::BaseClass*>(Base::Type::createInstanceByName(cName.c_str(),true));
00361     if (base) {
00362         // type not derived from ViewProviderDocumentObject!!!
00363         assert(base->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId()));
00364         ViewProviderDocumentObject *pcProvider = static_cast<ViewProviderDocumentObject*>(base);
00365         d->_ViewProviderMap[&Obj] = pcProvider;
00366 
00367         try {
00368             // if succesfully created set the right name and calculate the view
00369             //FIXME: Consider to change argument of attach() to const pointer
00370             pcProvider->attach(const_cast<App::DocumentObject*>(&Obj));
00371             pcProvider->updateView();
00372             pcProvider->setActiveMode();
00373         }
00374         catch(const Base::MemoryException& e){
00375             Base::Console().Error("Memory exception in '%s' thrown: %s\n",Obj.getNameInDocument(),e.what());
00376         }
00377         catch(Base::Exception &e){
00378             e.ReportException();
00379         }
00380 #ifndef FC_DEBUG
00381         catch(...){
00382             Base::Console().Error("App::Document::_RecomputeFeature(): Unknown exception in Feature \"%s\" thrown\n",Obj.getNameInDocument());
00383         }
00384 #endif
00385         std::list<Gui::BaseView*>::iterator vIt;
00386         // cycling to all views of the document
00387         for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) {
00388             View3DInventor *activeView = dynamic_cast<View3DInventor *>(*vIt);
00389             if (activeView)
00390                 activeView->getViewer()->addViewProvider(pcProvider);
00391         }
00392     
00393         // adding to the tree
00394         signalNewObject(*pcProvider);
00395     }
00396     else {
00397         Base::Console().Warning("Gui::Document::slotNewObject() no view provider for the object %s found\n",cName.c_str());
00398     }
00399 }
00400 
00401 void Document::slotDeletedObject(const App::DocumentObject& Obj)
00402 {
00403     std::list<Gui::BaseView*>::iterator vIt;
00404     setModified(true);
00405     //Base::Console().Log("Document::slotDeleteObject() called\n");
00406   
00407     // cycling to all views of the document
00408     ViewProvider* viewProvider = getViewProvider(&Obj);
00409     for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) {
00410         View3DInventor *activeView = dynamic_cast<View3DInventor *>(*vIt);
00411         if (activeView && viewProvider) {
00412             if (d->_pcInEdit == viewProvider)
00413                 resetEdit();
00414             activeView->getViewer()->removeViewProvider(viewProvider);
00415         }
00416     }
00417 
00418     if (viewProvider && viewProvider->getTypeId().isDerivedFrom(
00419         ViewProviderDocumentObject::getClassTypeId())) {
00420         // removing from tree
00421         signalDeletedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
00422 
00423         delete viewProvider;
00424         d->_ViewProviderMap.erase(&Obj);
00425     }
00426 }
00427 
00428 void Document::slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop)
00429 {
00430     //Base::Console().Log("Document::slotChangedObject() called\n");
00431     ViewProvider* viewProvider = getViewProvider(&Obj);
00432     if (viewProvider) {
00433         try {
00434             viewProvider->update(&Prop);
00435         } catch(const Base::MemoryException& e) {
00436             Base::Console().Error("Memory exception in '%s' thrown: %s\n",Obj.getNameInDocument(),e.what());
00437         } catch(Base::Exception &e){
00438             e.ReportException();
00439         } catch (...) {
00440             Base::Console().Error("Cannot update representation for '%s'.\n", Obj.getNameInDocument());
00441         }
00442 
00443         if (viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
00444             signalChangedObject(static_cast<ViewProviderDocumentObject&>(*viewProvider), Prop);
00445     }
00446 
00447     // a property of an object has changed
00448     setModified(true);
00449 }
00450 
00451 void Document::slotRenamedObject(const App::DocumentObject& Obj)
00452 {
00453     ViewProvider* viewProvider = getViewProvider(&Obj);
00454     if (viewProvider && viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
00455         signalRenamedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
00456     }
00457 }
00458 
00459 void Document::slotActivatedObject(const App::DocumentObject& Obj)
00460 {
00461     ViewProvider* viewProvider = getViewProvider(&Obj);
00462     if (viewProvider && viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
00463         signalActivatedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
00464     }
00465 }
00466 
00467 void Document::setModified(bool b)
00468 {
00469     d->_isModified = b;
00470     
00471     std::list<MDIView*> mdis = getMDIViews();
00472     for (std::list<MDIView*>::iterator it = mdis.begin(); it != mdis.end(); ++it) {
00473         (*it)->setWindowModified(b);
00474     }
00475 }
00476 
00477 bool Document::isModified() const
00478 {
00479     return d->_isModified;
00480 }
00481 
00482 App::Document* Document::getDocument(void) const
00483 {
00484     return d->_pcDocument;
00485 }
00486 
00488 bool Document::save(void)
00489 {
00490     if (d->_pcDocument->isSaved()) {
00491         Gui::WaitCursor wc;
00492         Command::doCommand(Command::Doc,"App.getDocument(\"%s\").save()"
00493                                        ,d->_pcDocument->getName());
00494         setModified(false);
00495         return true;
00496     }
00497     else {
00498         return saveAs();
00499     }
00500 }
00501 
00503 bool Document::saveAs(void)
00504 {
00505     getMainWindow()->statusBar()->showMessage(QObject::tr("Save document under new filename..."));
00506 
00507     QString exe = QString::fromUtf8(App::GetApplication().getExecutableName());
00508     QString fn = QFileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe), 
00509                  FileDialog::getWorkingDirectory(), QObject::tr("%1 document (*.FCStd)").arg(exe));
00510     if (!fn.isEmpty()) {
00511         FileDialog::setWorkingDirectory(fn);
00512         QString file = fn.toLower();
00513         if (!file.endsWith(QLatin1String(".fcstd"))) {
00514             fn += QLatin1String(".fcstd");
00515             QFileInfo fi;
00516             fi.setFile(fn);
00517             if (fi.exists()) {
00518                 // if we auto-append the extension make sure that we don't override an existing file
00519                 int ret = QMessageBox::question(getMainWindow(), QObject::tr("Save As"), 
00520                     QObject::tr("%1 already exists.\n"
00521                                 "Do you want to replace it?").arg(fn),
00522                                 QMessageBox::Yes|QMessageBox::Default,
00523                                 QMessageBox::No|QMessageBox::Escape); 
00524                 if (ret != QMessageBox::Yes)
00525                     fn = QString();
00526             }
00527         }
00528     }
00529 
00530     if (!fn.isEmpty()) {
00531         QFileInfo fi;
00532         fi.setFile(fn);
00533         QString bn = fi.baseName();
00534 
00535         const char * DocName = App::GetApplication().getDocumentName(getDocument());
00536 
00537         // save as new file name
00538         Gui::WaitCursor wc;
00539         Command::doCommand(Command::Doc,"App.getDocument(\"%s\").FileName = \"%s\""
00540                                        , DocName, (const char*)fn.toUtf8());
00541         Command::doCommand(Command::Doc,"App.getDocument(\"%s\").Label = \"%s\""
00542                                        , DocName, (const char*)bn.toUtf8());
00543         Command::doCommand(Command::Doc,"App.getDocument(\"%s\").save()"
00544                                        , DocName);
00545         setModified(false);
00546 
00547         getMainWindow()->appendRecentFile(fi.filePath());
00548         return true;
00549     }
00550     else {
00551         getMainWindow()->statusBar()->showMessage(QObject::tr("Saving aborted"), 2000);
00552         return false;
00553     }
00554 }
00555 
00556 unsigned int Document::getMemSize (void) const
00557 {
00558     unsigned int size = 0;
00559 
00560     // size of the view providers in the document
00561     std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator it;
00562     for (it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it)
00563         size += it->second->getMemSize();
00564     return size;
00565 }
00566 
00570 void Document::Save (Base::Writer &writer) const
00571 {
00572     // It's only possible to add extra information if force of XML is disabled
00573     if (writer.isForceXML() == false) {
00574         writer.addFile("GuiDocument.xml", this);
00575 
00576         if (App::GetApplication().GetParameterGroupByPath
00577             ("User parameter:BaseApp/Preferences/Document")->GetBool("SaveThumbnail",false)) {
00578             std::list<MDIView*> mdi = getMDIViews();
00579             for (std::list<MDIView*>::iterator it = mdi.begin(); it != mdi.end(); ++it) {
00580                 if ((*it)->getTypeId().isDerivedFrom(View3DInventor::getClassTypeId())) {
00581                     View3DInventorViewer* view = static_cast<View3DInventor*>(*it)->getViewer();
00582                     d->thumb.setFileName(d->_pcDocument->FileName.getValue());
00583                     d->thumb.setSize(128);
00584                     d->thumb.setViewer(view);
00585                     d->thumb.Save(writer);
00586                     break;
00587                 }
00588             }
00589         }
00590     }
00591 }
00592 
00596 void Document::Restore(Base::XMLReader &reader)
00597 {
00598     reader.addFile("GuiDocument.xml",this);
00599     // hide all elements to avoid to update the 3d view when loading data files
00600     // RestoreDocFile then restores the visibility status again
00601     std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::iterator it;
00602     for (it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it) {
00603         it->second->hide();
00604         it->second->startRestoring();
00605     }
00606 }
00607 
00611 void Document::RestoreDocFile(Base::Reader &reader)
00612 {
00613     // We must create an XML parser to read from the input stream
00614     Base::XMLReader xmlReader("GuiDocument.xml", reader);
00615 
00616     int i,Cnt;
00617 
00618     xmlReader.readElement("Document");
00619     long scheme = xmlReader.getAttributeAsInteger("SchemaVersion");
00620 
00621     // At this stage all the document objects and their associated view providers exist.
00622     // Now we must restore the properties of the view providers only.
00623     //
00624     // SchemeVersion "1"
00625     if (scheme == 1) {
00626         // read the viewproviders itself
00627         xmlReader.readElement("ViewProviderData");
00628         Cnt = xmlReader.getAttributeAsInteger("Count");
00629         for (i=0 ;i<Cnt ;i++) {
00630             xmlReader.readElement("ViewProvider");
00631             std::string name = xmlReader.getAttribute("name");
00632             ViewProvider* pObj = getViewProviderByName(name.c_str());
00633             if (pObj) // check if this feature has been registered
00634                 pObj->Restore(xmlReader);
00635             xmlReader.readEndElement("ViewProvider");
00636         }
00637         xmlReader.readEndElement("ViewProviderData");
00638 
00639         // read camera settings
00640         xmlReader.readElement("Camera");
00641         const char* ppReturn = xmlReader.getAttribute("settings");
00642         std::string sMsg = "SetCamera ";
00643         sMsg += ppReturn;
00644         if (strcmp(ppReturn, "") != 0) { // non-empty attribute
00645             if (d->_pcAppWnd->sendHasMsgToActiveView("SetCamera"))
00646                 d->_pcAppWnd->sendMsgToActiveView(sMsg.c_str());
00647         }
00648     }
00649 
00650     xmlReader.readEndElement("Document");
00651 
00652     // In the file GuiDocument.xml new data files might be added
00653     if (!xmlReader.getFilenames().empty())
00654         xmlReader.readFiles(static_cast<zipios::ZipInputStream&>(reader));
00655 
00656     // reset modifeid flag
00657     setModified(false);
00658 }
00659 
00660 void Document::slotRestoredDocument(const App::Document&)
00661 {
00662     // some post-processing of view providers
00663     std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::iterator it;
00664     for (it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it) {
00665         it->second->finishRestoring();
00666     }
00667 }
00668 
00672 void Document::SaveDocFile (Base::Writer &writer) const
00673 {
00674     writer.Stream() << "<?xml version='1.0' encoding='utf-8'?>" << std::endl
00675                     << "<!--" << std::endl
00676                     << " FreeCAD Document, see http://free-cad.sourceforge.net for more information..."
00677                     << std::endl << "-->" << std::endl;
00678 
00679     writer.Stream() << "<Document SchemaVersion=\"1\">" << std::endl;
00680 
00681     std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator it;
00682 
00683     // writing the view provider names itself
00684     writer.incInd(); // indention for 'ViewProviderData Count'
00685     writer.Stream() << writer.ind() << "<ViewProviderData Count=\"" 
00686                     << d->_ViewProviderMap.size() <<"\">" << std::endl;
00687 
00688     bool xml = writer.isForceXML();
00689     //writer.setForceXML(true);
00690     writer.incInd(); // indention for 'ViewProvider name'
00691     for(it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it) {
00692         const App::DocumentObject* doc = it->first;
00693         ViewProvider* obj = it->second;
00694         writer.Stream() << writer.ind() << "<ViewProvider name=\""
00695                         << doc->getNameInDocument() << "\">" << std::endl;
00696         obj->Save(writer);
00697         writer.Stream() << writer.ind() << "</ViewProvider>" << std::endl;
00698     }
00699     writer.setForceXML(xml);
00700 
00701     writer.decInd(); // indention for 'ViewProvider name'
00702     writer.Stream() << writer.ind() << "</ViewProviderData>" << std::endl;
00703     writer.decInd();  // indention for 'ViewProviderData Count'
00704 
00705     // set camera settings
00706     QString viewPos;
00707     if (d->_pcAppWnd->sendHasMsgToActiveView("GetCamera")) {
00708         const char* ppReturn=0;
00709         d->_pcAppWnd->sendMsgToActiveView("GetCamera",&ppReturn);
00710   
00711         // remove the first line because it's a comment like '#Inventor V2.1 ascii'
00712         QStringList lines = QString(QString::fromAscii(ppReturn)).split(QLatin1String("\n"));
00713         if (lines.size() > 1) {
00714             lines.pop_front();
00715             viewPos = lines.join(QLatin1String(" "));
00716         }
00717     }
00718 
00719     writer.incInd(); // indention for camera settings
00720     writer.Stream() << writer.ind() << "<Camera settings=\"" 
00721                     << (const char*)viewPos.toAscii() <<"\"/>" << std::endl;
00722     writer.decInd(); // indention for camera settings
00723     writer.Stream() << "</Document>" << std::endl;
00724 }
00725 
00726 void Document::exportObjects(const std::vector<App::DocumentObject*>& obj, Base::Writer& writer)
00727 {
00728     writer.Stream() << "<?xml version='1.0' encoding='utf-8'?>" << std::endl;
00729     writer.Stream() << "<Document SchemaVersion=\"1\">" << std::endl;
00730 
00731     std::map<const App::DocumentObject*,ViewProvider*> views;
00732     for (std::vector<App::DocumentObject*>::const_iterator it = obj.begin(); it != obj.end(); ++it) {
00733         Document* doc = Application::Instance->getDocument((*it)->getDocument());
00734         if (doc) {
00735             ViewProvider* vp = doc->getViewProvider(*it);
00736             if (vp) views[*it] = vp;
00737         }
00738     }
00739 
00740     // writing the view provider names itself
00741     writer.incInd(); // indention for 'ViewProviderData Count'
00742     writer.Stream() << writer.ind() << "<ViewProviderData Count=\"" 
00743                     << views.size() <<"\">" << std::endl;
00744 
00745     bool xml = writer.isForceXML();
00746     writer.setForceXML(true);
00747     writer.incInd(); // indention for 'ViewProvider name'
00748     std::map<const App::DocumentObject*,ViewProvider*>::const_iterator jt;
00749     for (jt = views.begin(); jt != views.end(); ++jt) {
00750         const App::DocumentObject* doc = jt->first;
00751         ViewProvider* obj = jt->second;
00752         writer.Stream() << writer.ind() << "<ViewProvider name=\""
00753                         << doc->getNameInDocument() << "\" type=\""
00754                         << obj->getTypeId().getName()
00755                         << "\">" << std::endl;
00756         obj->Save(writer);
00757         writer.Stream() << writer.ind() << "</ViewProvider>" << std::endl;
00758     }
00759     writer.setForceXML(xml);
00760 
00761     writer.decInd(); // indention for 'ViewProvider name'
00762     writer.Stream() << writer.ind() << "</ViewProviderData>" << std::endl;
00763     writer.decInd();  // indention for 'ViewProviderData Count'
00764     writer.incInd(); // indention for camera settings
00765     writer.Stream() << writer.ind() << "<Camera settings=\"\"/>" << std::endl;
00766     writer.decInd(); // indention for camera settings
00767     writer.Stream() << "</Document>" << std::endl;
00768 }
00769 
00770 void Document::importObjects(const std::vector<App::DocumentObject*>& obj, Base::Reader& reader)
00771 {
00772     // We must create an XML parser to read from the input stream
00773     Base::XMLReader xmlReader("GuiDocument.xml", reader);
00774     xmlReader.readElement("Document");
00775     long scheme = xmlReader.getAttributeAsInteger("SchemaVersion");
00776 
00777     // At this stage all the document objects and their associated view providers exist.
00778     // Now we must restore the properties of the view providers only.
00779     //
00780     // SchemeVersion "1"
00781     if (scheme == 1) {
00782         // read the viewproviders itself
00783         xmlReader.readElement("ViewProviderData");
00784         int Cnt = xmlReader.getAttributeAsInteger("Count");
00785         std::vector<App::DocumentObject*>::const_iterator it = obj.begin();
00786         for (int i=0;i<Cnt&&it!=obj.end();++i,++it) {
00787             // The stored name usually doesn't match with the current name anymore
00788             // thus we try to match by type. This should work because the order of
00789             // objects should not have changed
00790             xmlReader.readElement("ViewProvider");
00791             std::string type = xmlReader.getAttribute("type");
00792             ViewProvider* pObj = getViewProvider(*it);
00793             while (pObj && type != pObj->getTypeId().getName()) {
00794                 if (it != obj.end()) {
00795                     ++it;
00796                     pObj = getViewProvider(*it);
00797                 }
00798             }
00799             if (pObj && type == pObj->getTypeId().getName())
00800                 pObj->Restore(xmlReader);
00801             xmlReader.readEndElement("ViewProvider");
00802             if (it == obj.end())
00803                 break;
00804         }
00805         xmlReader.readEndElement("ViewProviderData");
00806     }
00807 
00808     xmlReader.readEndElement("Document");
00809 }
00810 
00811 void Document::createView(const char* sType) 
00812 {
00813     View3DInventor* view3D = new View3DInventor(this, getMainWindow());
00814 
00815     // attach the viewprovider
00816     std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator It1;
00817     for (It1=d->_ViewProviderMap.begin();It1!=d->_ViewProviderMap.end();++It1)
00818         view3D->getViewer()->addViewProvider(It1->second);
00819     std::map<std::string,ViewProvider*>::const_iterator It2;
00820     for (It2=d->_ViewProviderMapAnnotation.begin();It2!=d->_ViewProviderMapAnnotation.end();++It2)
00821         view3D->getViewer()->addViewProvider(It2->second);
00822 
00823     const char* name = getDocument()->Label.getValue();
00824 
00825     QString title = QString::fromAscii("%1 : %2[*]")
00826         .arg(QString::fromUtf8(name)).arg(d->_iWinCount++);
00827 
00828     view3D->setWindowTitle(title);
00829     view3D->setWindowIcon(QApplication::windowIcon());
00830     view3D->resize(400, 300);
00831     getMainWindow()->addWindow(view3D);
00832 }
00833 
00834 void Document::attachView(Gui::BaseView* pcView, bool bPassiv)
00835 {
00836     if (!bPassiv)
00837         d->baseViews.push_back(pcView);
00838     else
00839         d->passiveViews.push_back(pcView);
00840 }
00841 
00842 void Document::detachView(Gui::BaseView* pcView, bool bPassiv)
00843 {
00844     if (bPassiv) {
00845         if (find(d->passiveViews.begin(),d->passiveViews.end(),pcView)
00846             != d->passiveViews.end())
00847         d->passiveViews.remove(pcView);
00848     }
00849     else {
00850         if (find(d->baseViews.begin(),d->baseViews.end(),pcView)
00851             != d->baseViews.end())
00852         d->baseViews.remove(pcView);
00853 
00854         // last view?
00855         if (d->baseViews.size() == 0) {
00856             // decouple a passive view
00857             std::list<Gui::BaseView*>::iterator it = d->passiveViews.begin();
00858             while (it != d->passiveViews.end()) {
00859                 (*it)->setDocument(0);
00860                 it = d->passiveViews.begin();
00861             }
00862 
00863             // is already  closing the document
00864             if (d->_isClosing == false)
00865                 d->_pcAppWnd->onLastWindowClosed(this);
00866         }
00867     }
00868 }
00869 
00870 void Document::onUpdate(void)
00871 {
00872 #ifdef FC_LOGUPDATECHAIN
00873     Base::Console().Log("Acti: Gui::Document::onUpdate()");
00874 #endif
00875 
00876     std::list<Gui::BaseView*>::iterator it;
00877 
00878     for (it = d->baseViews.begin();it != d->baseViews.end();++it) {
00879         (*it)->onUpdate();
00880     }
00881 
00882     for (it = d->passiveViews.begin();it != d->passiveViews.end();++it) {
00883         (*it)->onUpdate();
00884     }
00885 }
00886 
00887 void Document::onRelabel(void)
00888 {
00889 #ifdef FC_LOGUPDATECHAIN
00890     Base::Console().Log("Acti: Gui::Document::onRelabel()");
00891 #endif
00892 
00893     std::list<Gui::BaseView*>::iterator it;
00894 
00895     for (it = d->baseViews.begin();it != d->baseViews.end();++it) {
00896         (*it)->onRelabel(this);
00897     }
00898 
00899     for (it = d->passiveViews.begin();it != d->passiveViews.end();++it) {
00900         (*it)->onRelabel(this);
00901     }
00902 }
00903 
00904 bool Document::isLastView(void)
00905 {
00906     if (d->baseViews.size() <= 1)
00907         return true;
00908     return false;
00909 }
00910 
00915 bool Document::canClose ()
00916 {
00917     if (!getDocument()->isClosable()) {
00918         QMessageBox::warning(getActiveView(),
00919             QObject::tr("Document not closable"),
00920             QObject::tr("The document is not closable for the moment."));
00921         return false;
00922     }
00923     else if (!Gui::Control().isAllowedAlterDocument()) {
00924         QMessageBox::warning(getActiveView(),
00925             QObject::tr("Document not closable"),
00926             QObject::tr("The document is in editing mode and thus cannot be closed for the moment.\n"
00927                         "You either have to finish or cancel the editing in the task panel."));
00928         Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
00929         if (dlg) Gui::Control().showDialog(dlg);
00930         return false;
00931     }
00932 
00933     if (!isModified())
00934         return true;
00935     bool ok = true;
00936     switch(QMessageBox::question(getActiveView(),
00937         QObject::tr("Unsaved document"),
00938         QObject::tr("Save document before close?"),
00939         QMessageBox::Yes | QMessageBox::Default,
00940         QMessageBox::No,
00941         QMessageBox::Cancel | QMessageBox::Escape))
00942     {
00943     case QMessageBox::Yes:
00944         ok = save();
00945         break;
00946     case QMessageBox::No:
00947         ok = true;
00948         break;
00949     case QMessageBox::Cancel:
00950         ok = false;
00951         break;
00952     }
00953 
00954     return ok;
00955 }
00956 
00957 std::list<MDIView*> Document::getMDIViews() const
00958 {
00959     std::list<MDIView*> views;
00960     for (std::list<BaseView*>::const_iterator it = d->baseViews.begin();
00961          it != d->baseViews.end(); ++it) {
00962         MDIView* view = dynamic_cast<MDIView*>(*it);
00963         if (view)
00964             views.push_back(view);
00965     }
00966 
00967     return views;
00968 }
00969 
00971 bool Document::sendMsgToViews(const char* pMsg)
00972 {
00973     std::list<Gui::BaseView*>::iterator it;
00974     const char** pReturnIgnore=0;
00975 
00976     for (it = d->baseViews.begin();it != d->baseViews.end();++it) {
00977         if ((*it)->onMsg(pMsg,pReturnIgnore)) {
00978             return true;
00979         }
00980     }
00981 
00982     for (it = d->passiveViews.begin();it != d->passiveViews.end();++it) {
00983         if ((*it)->onMsg(pMsg,pReturnIgnore)) {
00984             return true;
00985         }
00986     }
00987 
00988     return false;
00989 }
00990 
00992 MDIView* Document::getActiveView(void) const
00993 {
00994     // get the main window's active view 
00995     MDIView* active = getMainWindow()->activeWindow();
00996 
00997     // get all MDI views of the document
00998     std::list<MDIView*> mdis = getMDIViews();
00999 
01000     // check whether the active view is part of this document
01001     bool ok=false;
01002     for (std::list<MDIView*>::const_iterator it = mdis.begin(); it != mdis.end(); ++it) {
01003         if ((*it) == active) {
01004             ok = true;
01005             break;
01006         }
01007     }
01008 
01009     // the active view is not part of this document, just use the first view
01010     if (!ok && !mdis.empty())
01011         active = mdis.front();
01012 
01013     return active;
01014 }
01015 
01016 
01017 //--------------------------------------------------------------------------
01018 // UNDO REDO transaction handling  
01019 //--------------------------------------------------------------------------
01028 void Document::openCommand(const char* sName)
01029 {
01030     getDocument()->openTransaction(sName);
01031 }
01032 
01033 void Document::commitCommand(void)
01034 {
01035     getDocument()->commitTransaction(); 
01036 }
01037 
01038 void Document::abortCommand(void)
01039 {
01040     getDocument()->abortTransaction();  
01041 }
01042 
01044 std::vector<std::string> Document::getUndoVector(void) const
01045 {
01046     return getDocument()->getAvailableUndoNames();
01047 }
01048 
01050 std::vector<std::string> Document::getRedoVector(void) const
01051 {
01052     return getDocument()->getAvailableRedoNames();
01053 }
01054 
01056 void Document::undo(int iSteps)
01057 {
01058     for (int i=0;i<iSteps;i++) {
01059         getDocument()->undo();
01060     }
01061 }
01062 
01064 void Document::redo(int iSteps)
01065 {
01066     for (int i=0;i<iSteps;i++) {
01067         getDocument()->redo();
01068     }
01069 }
01070 
01071 PyObject* Document::getPyObject(void)
01072 {
01073     _pcDocPy->IncRef();
01074     return _pcDocPy;
01075 }

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