~ubuntu-branches/ubuntu/maverick/freecad/maverick

« back to all changes in this revision

Viewing changes to src/Gui/Document.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Teemu Ikonen
  • Date: 2009-07-16 18:37:41 UTC
  • Revision ID: james.westby@ubuntu.com-20090716183741-oww9kcxqrk991i1n
Tags: upstream-0.8.2237
ImportĀ upstreamĀ versionĀ 0.8.2237

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (c) 2004 Jļæ½rgen Riegel <juergen.riegel@web.de>              *
 
3
 *                                                                         *
 
4
 *   This file is part of the FreeCAD CAx development system.              *
 
5
 *                                                                         *
 
6
 *   This library is free software; you can redistribute it and/or         *
 
7
 *   modify it under the terms of the GNU Library General Public           *
 
8
 *   License as published by the Free Software Foundation; either          *
 
9
 *   version 2 of the License, or (at your option) any later version.      *
 
10
 *                                                                         *
 
11
 *   This library  is distributed in the hope that it will be useful,      *
 
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
14
 *   GNU Library General Public License for more details.                  *
 
15
 *                                                                         *
 
16
 *   You should have received a copy of the GNU Library General Public     *
 
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
 
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 
20
 *                                                                         *
 
21
 ***************************************************************************/
 
22
 
 
23
 
 
24
#include "PreCompiled.h"
 
25
 
 
26
#ifndef _PreComp_
 
27
# include <qdir.h>
 
28
# include <qfileinfo.h>
 
29
# include <qmessagebox.h>
 
30
# include <qstatusbar.h>
 
31
# include <boost/signals.hpp>
 
32
# include <boost/bind.hpp>
 
33
#endif
 
34
 
 
35
#include <Base/Console.h>
 
36
#include <Base/Exception.h>
 
37
#include <Base/Matrix.h>
 
38
#include <Base/Reader.h>
 
39
#include <Base/Writer.h>
 
40
 
 
41
#include <App/Document.h>
 
42
#include <App/DocumentObject.h>
 
43
 
 
44
#include "Application.h"
 
45
#include "MainWindow.h"
 
46
#include "Tree.h"
 
47
#include "Document.h"
 
48
#include "DocumentPy.h"
 
49
#include "Command.h"
 
50
#include "FileDialog.h"
 
51
#include "View3DInventor.h"
 
52
#include "View3DInventorViewer.h"
 
53
#include "BitmapFactory.h"
 
54
#include "ViewProviderDocumentObject.h"
 
55
#include "Selection.h"
 
56
#include "SoFCSelection.h"
 
57
#include "WaitCursor.h"
 
58
#include "Thumbnail.h"
 
59
 
 
60
using namespace Gui;
 
61
 
 
62
namespace Gui {
 
63
 
 
64
// Pimpl class
 
65
struct DocumentP
 
66
{
 
67
    Thumbnail thumb;
 
68
    int        _iWinCount;
 
69
    int        _iDocId;
 
70
    bool       _isClosing;
 
71
    bool       _isModified;
 
72
    ViewProvider*   _pcInEdit;
 
73
    Application*    _pcAppWnd;
 
74
    // the doc/Document
 
75
    App::Document*  _pcDocument;
 
76
    /// List of all registered views
 
77
    std::list<Gui::BaseView*> _LpcViews;
 
78
    /// List of all registered views
 
79
    std::list<Gui::BaseView*> _LpcPassivViews;
 
80
    std::map<App::DocumentObject*,ViewProviderDocumentObject*> _ViewProviderMap;
 
81
    std::map<std::string,ViewProvider*> _ViewProviderMapAnnotation;
 
82
};
 
83
 
 
84
} // namespace Gui
 
85
 
 
86
/* TRANSLATOR Gui::Document */
 
87
 
 
88
int Document::_iDocCount = 0;
 
89
 
 
90
Document::Document(App::Document* pcDocument,Application * app)
 
91
{
 
92
    d = new DocumentP;
 
93
    d->_iWinCount = 1;
 
94
    // new instance
 
95
    d->_iDocId = (++_iDocCount);
 
96
    d->_isClosing = false;
 
97
    d->_isModified = false;
 
98
    d->_pcAppWnd = app;
 
99
    d->_pcDocument = pcDocument;
 
100
    d->_pcInEdit = 0;
 
101
 
 
102
    //pcDocument->m_sig.connect(boost::bind(&Gui::Document::refresh, this, _1));
 
103
    //boost::bind(&Gui::Document::slotNewObject, this, _1)
 
104
 
 
105
    //App::Document::connection_t  m_connection;
 
106
    //m_connection = pcDocument->connect(boost::bind(&Document::slotNewObject, this, _1));
 
107
    pcDocument->signalNewObject.connect(boost::bind(&Gui::Document::slotNewObject, this, _1));
 
108
    pcDocument->signalDeletedObject.connect(boost::bind(&Gui::Document::slotDeletedObject, this, _1));
 
109
    pcDocument->signalChangedObject.connect(boost::bind(&Gui::Document::slotChangedObject, this, _1, _2));
 
110
    pcDocument->signalRenamedObject.connect(boost::bind(&Gui::Document::slotRenamedObject, this, _1));
 
111
    pcDocument->signalActivatedObject.connect(boost::bind(&Gui::Document::slotActivatedObject, this, _1));
 
112
    //pcDocument->signalNewObject.connect(&(this->slotNewObject));
 
113
    pcDocument->signalSaveDocument.connect(boost::bind(&Gui::Document::Save, this, _1));
 
114
    pcDocument->signalRestoreDocument.connect(boost::bind(&Gui::Document::Restore, this, _1));
 
115
 
 
116
    // pointer to the python class
 
117
    // NOTE: As this Python object doesn't get returned to the interpreter we
 
118
    // mustn't increment it (Werner Jan-12-2006)
 
119
    _pcDocPy = new Gui::DocumentPy(this);
 
120
 
 
121
    if (App::GetApplication().GetParameterGroupByPath
 
122
        ("User parameter:BaseApp/Preferences/Document")->GetBool("UsingUndo",false))
 
123
        d->_pcDocument->setUndoMode(1);
 
124
}
 
125
 
 
126
Document::~Document()
 
127
{
 
128
    // e.g. if document gets closed from within a Python command
 
129
    d->_isClosing = true;
 
130
    // Calls Document::detachView()
 
131
    while (d->_LpcViews.size() > 0)
 
132
        delete d->_LpcViews.front();
 
133
 
 
134
    std::map<App::DocumentObject*,ViewProviderDocumentObject*>::iterator it;
 
135
    for (it = d->_ViewProviderMap.begin();it != d->_ViewProviderMap.end(); ++it)
 
136
        delete it->second;
 
137
    std::map<std::string,ViewProvider*>::iterator it2;
 
138
    for (it2 = d->_ViewProviderMapAnnotation.begin();it2 != d->_ViewProviderMapAnnotation.end(); ++it2)
 
139
        delete it2->second;
 
140
 
 
141
    // remove the reference from the object
 
142
    _pcDocPy->setInvalid();
 
143
    _pcDocPy->DecRef();
 
144
    delete d;
 
145
}
 
146
 
 
147
//*****************************************************************************************************
 
148
// 3D viewer handling
 
149
//*****************************************************************************************************
 
150
 
 
151
bool Document::setEdit(Gui::ViewProvider* p, int ModNum)
 
152
{
 
153
    if (d->_pcInEdit)
 
154
        resetEdit();
 
155
    View3DInventor *pcIvView = dynamic_cast<View3DInventor *>(getActiveView());
 
156
    if (pcIvView && pcIvView->getViewer()->setEdit(p,ModNum)) {
 
157
        d->_pcInEdit = p;
 
158
        if (d->_pcInEdit->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) 
 
159
            signalInEdit(*(static_cast<ViewProviderDocumentObject*>(d->_pcInEdit)));
 
160
    }
 
161
    else
 
162
        return false;
 
163
    return true;
 
164
}
 
165
 
 
166
void Document::resetEdit(void)
 
167
{
 
168
    std::list<Gui::BaseView*>::iterator VIt;
 
169
    if (d->_pcInEdit){
 
170
        for (VIt = d->_LpcViews.begin();VIt != d->_LpcViews.end();VIt++) {
 
171
            View3DInventor *pcIvView = dynamic_cast<View3DInventor *>(*VIt);
 
172
            if (pcIvView)
 
173
                pcIvView->getViewer()->resetEdit();
 
174
        }
 
175
 
 
176
        if (d->_pcInEdit->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) 
 
177
            signalResetEdit(*(static_cast<ViewProviderDocumentObject*>(d->_pcInEdit)));
 
178
        d->_pcInEdit = 0;
 
179
    }
 
180
}
 
181
 
 
182
ViewProvider *Document::getInEdit(void) const
 
183
{
 
184
    return d->_pcInEdit;
 
185
}
 
186
 
 
187
void Document::setAnnotationViewProvider(const char* name, ViewProvider *pcProvider)
 
188
{
 
189
    std::list<Gui::BaseView*>::iterator VIt;
 
190
 
 
191
    // already in ?
 
192
    std::map<std::string,ViewProvider*>::iterator it = d->_ViewProviderMapAnnotation.find(name);
 
193
    if (it != d->_ViewProviderMapAnnotation.end())
 
194
        removeAnnotationViewProvider(name);
 
195
 
 
196
    // add 
 
197
    d->_ViewProviderMapAnnotation[name] = pcProvider;
 
198
 
 
199
    // cycling to all views of the document
 
200
    for(VIt = d->_LpcViews.begin();VIt != d->_LpcViews.end();VIt++) {
 
201
        View3DInventor *pcIvView = dynamic_cast<View3DInventor *>(*VIt);
 
202
        if (pcIvView)
 
203
            pcIvView->getViewer()->addViewProvider(pcProvider);
 
204
    }
 
205
}
 
206
 
 
207
ViewProvider * Document::getAnnotationViewProvider(const char* name) const
 
208
{
 
209
    std::map<std::string,ViewProvider*>::const_iterator it = d->_ViewProviderMapAnnotation.find(name);
 
210
    return ( (it != d->_ViewProviderMapAnnotation.end()) ? it->second : 0 );
 
211
}
 
212
 
 
213
void Document::removeAnnotationViewProvider(const char* name)
 
214
{
 
215
    std::map<std::string,ViewProvider*>::iterator it = d->_ViewProviderMapAnnotation.find(name);
 
216
    std::list<Gui::BaseView*>::iterator VIt;
 
217
 
 
218
    // cycling to all views of the document
 
219
    for (VIt = d->_LpcViews.begin();VIt != d->_LpcViews.end();VIt++) {
 
220
        View3DInventor *pcIvView = dynamic_cast<View3DInventor *>(*VIt);
 
221
        if (pcIvView)
 
222
            pcIvView->getViewer()->removeViewProvider(it->second);
 
223
    }
 
224
 
 
225
    delete it->second;
 
226
    d->_ViewProviderMapAnnotation.erase(it); 
 
227
}
 
228
 
 
229
 
 
230
ViewProvider* Document::getViewProvider(App::DocumentObject* Feat) const
 
231
{
 
232
    std::map<App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator
 
233
    it = d->_ViewProviderMap.find( Feat );
 
234
    return ( (it != d->_ViewProviderMap.end()) ? it->second : 0 );
 
235
}
 
236
 
 
237
std::vector<ViewProvider*> Document::getViewProvidersOfType(const Base::Type& typeId) const
 
238
{
 
239
    std::vector<ViewProvider*> Objects;
 
240
    for (std::map<App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator it = 
 
241
         d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it ) {
 
242
        if (it->second->getTypeId().isDerivedFrom(typeId))
 
243
            Objects.push_back(it->second);
 
244
    }
 
245
    return Objects;
 
246
}
 
247
 
 
248
ViewProvider *Document::getViewProviderByName(const char* name) const
 
249
{
 
250
    // first check on feature name
 
251
    App::DocumentObject *pcFeat = getDocument()->getObject(name);
 
252
 
 
253
    if (pcFeat)
 
254
    {
 
255
        std::map<App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator
 
256
        it = d->_ViewProviderMap.find( pcFeat );
 
257
 
 
258
        if (it != d->_ViewProviderMap.end())
 
259
            return it->second;
 
260
    } else {
 
261
        // then try annotation name
 
262
        std::map<std::string,ViewProvider*>::const_iterator it2 = d->_ViewProviderMapAnnotation.find( name );
 
263
 
 
264
        if (it2 != d->_ViewProviderMapAnnotation.end())
 
265
            return it2->second;
 
266
    }
 
267
 
 
268
    return 0;
 
269
}
 
270
 
 
271
bool Document::isShow(const char* name)
 
272
{
 
273
    ViewProvider* pcProv = getViewProviderByName(name);
 
274
    return pcProv ? pcProv->isShow() : false;
 
275
}
 
276
 
 
277
/// put the feature in show
 
278
void Document::setShow(const char* name)
 
279
{
 
280
    ViewProvider* pcProv = getViewProviderByName(name);
 
281
 
 
282
    if (pcProv && pcProv->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
 
283
        ((ViewProviderDocumentObject*)pcProv)->Visibility.setValue(true);
 
284
    }
 
285
}
 
286
 
 
287
/// set the feature in Noshow
 
288
void Document::setHide(const char* name)
 
289
{
 
290
    ViewProvider* pcProv = getViewProviderByName(name);
 
291
 
 
292
    if (pcProv && pcProv->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
 
293
        ((ViewProviderDocumentObject*)pcProv)->Visibility.setValue(false);
 
294
    }
 
295
}
 
296
 
 
297
/// set the feature in Noshow
 
298
void Document::setPos(const char* name, const Base::Matrix4D& rclMtrx)
 
299
{
 
300
    ViewProvider* pcProv = getViewProviderByName(name);
 
301
    if (pcProv)
 
302
        pcProv->setTransformation(rclMtrx);
 
303
 
 
304
}
 
305
 
 
306
//*****************************************************************************************************
 
307
// Document
 
308
//*****************************************************************************************************
 
309
void Document::slotNewObject(App::DocumentObject& Obj)
 
310
{
 
311
    //Base::Console().Log("Document::slotNewObject() called\n");
 
312
    std::string cName = Obj.getViewProviderName();
 
313
    if (cName.empty()) {
 
314
        // handle document object with no view provider specified
 
315
        Base::Console().Log("%s has no view provider specified\n", Obj.getTypeId().getName());
 
316
        return;
 
317
    }
 
318
  
 
319
    setModified(true);
 
320
    Base::BaseClass* base = static_cast<Base::BaseClass*>(Base::Type::createInstanceByName(cName.c_str(),true));
 
321
    if (base) {
 
322
        // type not derived from ViewProviderDocumentObject!!!
 
323
        assert(base->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId()));
 
324
        ViewProviderDocumentObject *pcProvider = static_cast<ViewProviderDocumentObject*>(base);
 
325
        d->_ViewProviderMap[&Obj] = pcProvider;
 
326
 
 
327
        try {
 
328
            // if succesfully created set the right name and calculate the view
 
329
            pcProvider->attach(&Obj);
 
330
            pcProvider->updateView();
 
331
            pcProvider->setActiveMode();
 
332
        }
 
333
        catch(const Base::MemoryException& e){
 
334
            Base::Console().Error("Memory exception in '%s' thrown: %s\n",Obj.getNameInDocument(),e.what());
 
335
        }
 
336
        catch(Base::Exception &e){
 
337
            e.ReportException();
 
338
        }
 
339
#ifndef FC_DEBUG
 
340
        catch(...){
 
341
            Base::Console().Error("App::Document::_RecomputeFeature(): Unknown exception in Feature \"%s\" thrown\n",Obj.getNameInDocument());
 
342
        }
 
343
#endif
 
344
        std::list<Gui::BaseView*>::iterator VIt;
 
345
        // cycling to all views of the document
 
346
        for (VIt = d->_LpcViews.begin();VIt != d->_LpcViews.end();VIt++) {
 
347
            View3DInventor *pcIvView = dynamic_cast<View3DInventor *>(*VIt);
 
348
            if(pcIvView)
 
349
                pcIvView->getViewer()->addViewProvider(pcProvider);
 
350
        }
 
351
    
 
352
        // adding to the tree
 
353
        signalNewObject(*pcProvider);
 
354
    }
 
355
    else {
 
356
        Base::Console().Warning("Gui::Document::slotNewObject() no view provider for the object %s found\n",cName.c_str());
 
357
    }
 
358
}
 
359
 
 
360
void Document::slotDeletedObject(App::DocumentObject& Obj)
 
361
{
 
362
    std::list<Gui::BaseView*>::iterator VIt;
 
363
    setModified(true);
 
364
    //Base::Console().Log("Document::slotDeleteObject() called\n");
 
365
  
 
366
    // cycling to all views of the document
 
367
    ViewProvider* viewProvider = getViewProvider(&Obj);
 
368
    for (VIt = d->_LpcViews.begin();VIt != d->_LpcViews.end();VIt++) {
 
369
        View3DInventor *pcIvView = dynamic_cast<View3DInventor *>(*VIt);
 
370
        if (pcIvView && viewProvider) {
 
371
            if (d->_pcInEdit == viewProvider)
 
372
                resetEdit();
 
373
            pcIvView->getViewer()->removeViewProvider(viewProvider);
 
374
        }
 
375
    }
 
376
 
 
377
    if (viewProvider && viewProvider->getTypeId().isDerivedFrom(
 
378
        ViewProviderDocumentObject::getClassTypeId())) {
 
379
        // removing from tree
 
380
        signalDeletedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
 
381
 
 
382
        delete viewProvider;
 
383
        d->_ViewProviderMap.erase(&Obj);
 
384
    }
 
385
}
 
386
 
 
387
void Document::slotChangedObject(App::DocumentObject& Obj, App::Property& Prop)
 
388
{
 
389
    //Base::Console().Log("Document::slotChangedObject() called\n");
 
390
    ViewProvider* viewProvider = getViewProvider(&Obj);
 
391
    if (viewProvider) {
 
392
        try {
 
393
            viewProvider->update(&Prop);
 
394
        } catch(const Base::MemoryException& e) {
 
395
            Base::Console().Error("Memory exception in '%s' thrown: %s\n",Obj.getNameInDocument(),e.what());
 
396
        } catch(Base::Exception &e){
 
397
            e.ReportException();
 
398
        } catch (...) {
 
399
            Base::Console().Error("Cannot update representation for '%s'.\n", Obj.getNameInDocument());
 
400
        }
 
401
 
 
402
        if (viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
 
403
            signalChangedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
 
404
    }
 
405
 
 
406
    // a property of an object has changed
 
407
    setModified(true);
 
408
}
 
409
 
 
410
void Document::slotRenamedObject(App::DocumentObject& Obj)
 
411
{
 
412
    ViewProvider* viewProvider = getViewProvider(&Obj);
 
413
    if (viewProvider && viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
 
414
        signalRenamedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
 
415
    }
 
416
}
 
417
 
 
418
void Document::slotActivatedObject(App::DocumentObject& Obj)
 
419
{
 
420
    ViewProvider* viewProvider = getViewProvider(&Obj);
 
421
    if (viewProvider && viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
 
422
        signalActivatedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
 
423
    }
 
424
}
 
425
 
 
426
void Document::setModified(bool b)
 
427
{
 
428
    d->_isModified = b;
 
429
    
 
430
    std::list<MDIView*> mdis = getMDIViews();
 
431
    for (std::list<MDIView*>::iterator it = mdis.begin(); it != mdis.end(); ++it) {
 
432
        (*it)->setWindowModified(b);
 
433
    }
 
434
}
 
435
 
 
436
bool Document::isModified() const
 
437
{
 
438
    return d->_isModified;
 
439
}
 
440
 
 
441
App::Document* Document::getDocument(void) const
 
442
{
 
443
    return d->_pcDocument;
 
444
}
 
445
 
 
446
/// Save the document
 
447
bool Document::save(void)
 
448
{
 
449
    if (d->_pcDocument->isSaved()) {
 
450
        Gui::WaitCursor wc;
 
451
        Command::doCommand(Command::Doc,"App.getDocument(\"%s\").save()"
 
452
                                       ,d->_pcDocument->getName());
 
453
        setModified(false);
 
454
        return true;
 
455
    }
 
456
    else {
 
457
        return saveAs();
 
458
    }
 
459
}
 
460
 
 
461
/// Save the document under a new file name
 
462
bool Document::saveAs(void)
 
463
{
 
464
    getMainWindow()->statusBar()->showMessage(QObject::tr("Save document under new filename..."));
 
465
 
 
466
    QString exe = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
 
467
    QString fn = QFileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe), 
 
468
                 QDir::currentPath(), QObject::tr("%1 document (*.FCStd)").arg(exe));
 
469
    if (!fn.isEmpty()) {
 
470
        QString file = fn.toLower();
 
471
        if (!file.endsWith(QLatin1String(".fcstd"))) {
 
472
            fn += QLatin1String(".fcstd");
 
473
            QFileInfo fi;
 
474
            fi.setFile(fn);
 
475
            if (fi.exists()) {
 
476
                // if we auto-append the extension make sure that we don't override an existing file
 
477
                int ret = QMessageBox::question(getMainWindow(), QObject::tr("Save As"), 
 
478
                    QObject::tr("%1 already exists.\n"
 
479
                                "Do you want to replace it?").arg(fn),
 
480
                                QMessageBox::Yes|QMessageBox::Default,
 
481
                                QMessageBox::No|QMessageBox::Escape); 
 
482
                if (ret != QMessageBox::Yes)
 
483
                    fn = QString();
 
484
            }
 
485
        }
 
486
    }
 
487
 
 
488
    if (!fn.isEmpty()) {
 
489
        QFileInfo fi;
 
490
        fi.setFile(fn);
 
491
        QString bn = fi.baseName();
 
492
 
 
493
        const char * DocName = App::GetApplication().getDocumentName(getDocument());
 
494
 
 
495
        // save as new file name
 
496
        Gui::WaitCursor wc;
 
497
        Command::doCommand(Command::Doc,"App.getDocument(\"%s\").FileName = \"%s\""
 
498
                                       , DocName, (const char*)fn.toUtf8());
 
499
        Command::doCommand(Command::Doc,"App.getDocument(\"%s\").Label = \"%s\""
 
500
                                       , DocName, (const char*)bn.toUtf8());
 
501
        Command::doCommand(Command::Doc,"App.getDocument(\"%s\").save()"
 
502
                                       , DocName);
 
503
        setModified(false);
 
504
 
 
505
        getMainWindow()->appendRecentFile(fi.filePath());
 
506
        return true;
 
507
    }
 
508
    else {
 
509
        getMainWindow()->statusBar()->showMessage(QObject::tr("Saving aborted"), 2000);
 
510
        return false;
 
511
    }
 
512
}
 
513
 
 
514
unsigned int Document::getMemSize (void) const
 
515
{
 
516
    unsigned int size = 0;
 
517
 
 
518
    // size of the view providers in the document
 
519
    std::map<App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator it;
 
520
    for (it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it)
 
521
        size += it->second->getMemSize();
 
522
    return size;
 
523
}
 
524
 
 
525
/** 
 
526
 * Adds a separate XML file to the projects file that contains information about the view providers.
 
527
 */
 
528
void Document::Save (Base::Writer &writer) const
 
529
{
 
530
    // It's only possible to add extra information if force of XML is disabled
 
531
    if (writer.isForceXML() == false) {
 
532
        writer.addFile("GuiDocument.xml", this);
 
533
 
 
534
        if (App::GetApplication().GetParameterGroupByPath
 
535
            ("User parameter:BaseApp/Preferences/Document")->GetBool("SaveThumbnail",false)) {
 
536
            std::list<MDIView*> mdi = getMDIViews();
 
537
            for (std::list<MDIView*>::iterator it = mdi.begin(); it != mdi.end(); ++it) {
 
538
                if ((*it)->getTypeId().isDerivedFrom(View3DInventor::getClassTypeId())) {
 
539
                    View3DInventorViewer* view = static_cast<View3DInventor*>(*it)->getViewer();
 
540
                    d->thumb.setFileName(d->_pcDocument->FileName.getValue());
 
541
                    d->thumb.setSize(128);
 
542
                    d->thumb.setViewer(view);
 
543
                    d->thumb.Save(writer);
 
544
                    break;
 
545
                }
 
546
            }
 
547
        }
 
548
    }
 
549
}
 
550
 
 
551
/** 
 
552
 * Loads a separate XML file from the projects file with information about the view providers.
 
553
 */
 
554
void Document::Restore(Base::XMLReader &reader)
 
555
{
 
556
    reader.addFile("GuiDocument.xml",this);
 
557
}
 
558
 
 
559
/**
 
560
 * Restores the properties of the view providers.
 
561
 */
 
562
void Document::RestoreDocFile(Base::Reader &reader)
 
563
{
 
564
    // We must create an XML parser to read from the input stream
 
565
    Base::XMLReader xmlReader("GuiDocument.xml", reader);
 
566
 
 
567
    int i,Cnt;
 
568
 
 
569
    xmlReader.readElement("Document");
 
570
    long scheme = xmlReader.getAttributeAsInteger("SchemaVersion");
 
571
 
 
572
    // At this stage all the document objects and their associated view providers exist.
 
573
    // Now we must restore the properties of the view providers only.
 
574
    //
 
575
    // SchemeVersion "1"
 
576
    if (scheme == 1) {
 
577
        // read the viewproviders itself
 
578
        xmlReader.readElement("ViewProviderData");
 
579
        Cnt = xmlReader.getAttributeAsInteger("Count");
 
580
        for (i=0 ;i<Cnt ;i++) {
 
581
            xmlReader.readElement("ViewProvider");
 
582
            std::string name = xmlReader.getAttribute("name");
 
583
            ViewProvider* pObj = getViewProviderByName(name.c_str());
 
584
            if (pObj) // check if this feature has been registered
 
585
            {
 
586
                pObj->Restore(xmlReader);
 
587
 
 
588
                // As the view providers don't get notified when their proprties
 
589
                // change while reading we must force this here
 
590
                std::map<std::string,App::Property*> Map;
 
591
                pObj->getPropertyMap(Map);
 
592
                for (std::map<std::string,App::Property*>::iterator it = Map.begin();
 
593
                     it != Map.end(); ++it)
 
594
                    it->second->touch();
 
595
            }
 
596
            xmlReader.readEndElement("ViewProvider");
 
597
        }
 
598
        xmlReader.readEndElement("ViewProviderData");
 
599
 
 
600
        // read camera settings
 
601
        xmlReader.readElement("Camera");
 
602
        const char* ppReturn = xmlReader.getAttribute("settings");
 
603
        std::string sMsg = "SetCamera ";
 
604
        sMsg += ppReturn;
 
605
        if (strcmp(ppReturn, "") != 0) { // non-empty attribute
 
606
            if (d->_pcAppWnd->sendHasMsgToActiveView("SetCamera"))
 
607
                d->_pcAppWnd->sendMsgToActiveView(sMsg.c_str());
 
608
        }
 
609
    }
 
610
 
 
611
    xmlReader.readEndElement("Document");
 
612
 
 
613
    // reset modifeid flag
 
614
    setModified(false);
 
615
}
 
616
 
 
617
/**
 
618
 * Saves the properties of the view providers.
 
619
 */
 
620
void Document::SaveDocFile (Base::Writer &writer) const
 
621
{
 
622
    writer.Stream() << "<?xml version='1.0' encoding='utf-8'?>" << std::endl
 
623
                    << "<!--" << std::endl
 
624
                    << " FreeCAD Document, see http://free-cad.sourceforge.net for more informations..."
 
625
                    << std::endl << "-->" << std::endl;
 
626
 
 
627
    writer.Stream() << "<Document SchemaVersion=\"1\">" << std::endl;
 
628
 
 
629
    std::map<App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator it;
 
630
 
 
631
    // writing the view provider names itself
 
632
    writer.incInd(); // indention for 'ViewProviderData Count'
 
633
    writer.Stream() << writer.ind() << "<ViewProviderData Count=\"" 
 
634
                    << d->_ViewProviderMap.size() <<"\">" << std::endl;
 
635
 
 
636
    bool xml = writer.isForceXML();
 
637
    writer.setForceXML(true);
 
638
    writer.incInd(); // indention for 'ViewProvider name'
 
639
    for(it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it) {
 
640
        App::DocumentObject* doc = it->first;
 
641
        ViewProvider* obj = it->second;
 
642
        writer.Stream() << writer.ind() << "<ViewProvider name=\""
 
643
                        << doc->getNameInDocument() << "\">" << std::endl;
 
644
        obj->Save(writer);
 
645
        writer.Stream() << writer.ind() << "</ViewProvider>" << std::endl;
 
646
    }
 
647
    writer.setForceXML(xml);
 
648
 
 
649
    writer.decInd(); // indention for 'ViewProvider name'
 
650
    writer.Stream() << writer.ind() << "</ViewProviderData>" << std::endl;
 
651
    writer.decInd();  // indention for 'ViewProviderData Count'
 
652
 
 
653
    // set camera settings
 
654
    QString viewPos;
 
655
    if (d->_pcAppWnd->sendHasMsgToActiveView("GetCamera")) {
 
656
        const char* ppReturn=0;
 
657
        d->_pcAppWnd->sendMsgToActiveView("GetCamera",&ppReturn);
 
658
  
 
659
        // remove the first line because it's a comment like '#Inventor V2.1 ascii'
 
660
        QStringList lines = QString(QString::fromAscii(ppReturn)).split(QLatin1String("\n"));
 
661
        if (lines.size() > 1) {
 
662
            lines.pop_front();
 
663
            viewPos = lines.join(QLatin1String(" "));
 
664
        }
 
665
    }
 
666
 
 
667
    writer.incInd(); // indention for camera settings
 
668
    writer.Stream() << writer.ind() << "<Camera settings=\"" 
 
669
                    << (const char*)viewPos.toAscii() <<"\"/>" << std::endl;
 
670
    writer.decInd(); // indention for camera settings
 
671
    writer.Stream() << "</Document>" << std::endl;
 
672
}
 
673
 
 
674
void Document::createView(const char* sType) 
 
675
{
 
676
    QPixmap FCIcon = Gui::BitmapFactory().pixmap(App::Application::Config()["AppIcon"].c_str());
 
677
    MDIView* pcView3D=0;
 
678
    if (strcmp(sType,"View3DIv") == 0){
 
679
        pcView3D = new Gui::View3DInventor(this,getMainWindow());
 
680
 
 
681
        // add the selction node of the document
 
682
        //((View3DInventor*)pcView3D)->getViewer()->addSelectionNode(pcSelection);
 
683
    
 
684
        // attach the viewprovider
 
685
        std::map<App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator It1;
 
686
        for (It1=d->_ViewProviderMap.begin();It1!=d->_ViewProviderMap.end();++It1)
 
687
            ((View3DInventor*)pcView3D)->getViewer()->addViewProvider(It1->second);
 
688
        std::map<std::string,ViewProvider*>::const_iterator It2;
 
689
        for (It2=d->_ViewProviderMapAnnotation.begin();It2!=d->_ViewProviderMapAnnotation.end();++It2)
 
690
            ((View3DInventor*)pcView3D)->getViewer()->addViewProvider(It2->second);
 
691
 
 
692
    } else /* if(strcmp(sType,"View3DOCC") == 0){
 
693
        pcView3D = new MDIView3D(this,_pcAppWnd,"View3DOCC");
 
694
    }else*/
 
695
    {
 
696
        Base::Console().Error("Document::createView(): Unknown view type: %s\n",sType);
 
697
        return;
 
698
    }
 
699
 
 
700
    const char* name = getDocument()->Label.getValue();
 
701
 
 
702
    QString aName = QString::fromAscii("%1 : %2[*]")
 
703
        .arg(QString::fromUtf8(name)).arg(d->_iWinCount++);
 
704
 
 
705
    pcView3D->setWindowTitle(aName);
 
706
    pcView3D->setWindowIcon(FCIcon);
 
707
    pcView3D->resize( 400, 300 );
 
708
    getMainWindow()->addWindow(pcView3D);
 
709
}
 
710
 
 
711
void Document::attachView(Gui::BaseView* pcView, bool bPassiv)
 
712
{
 
713
  if(!bPassiv)
 
714
    d->_LpcViews.push_back(pcView);
 
715
  else
 
716
    d->_LpcPassivViews.push_back(pcView);
 
717
}
 
718
 
 
719
void Document::detachView(Gui::BaseView* pcView, bool bPassiv)
 
720
{
 
721
    if (bPassiv) {
 
722
        if (find(d->_LpcPassivViews.begin(),d->_LpcPassivViews.end(),pcView)
 
723
            != d->_LpcPassivViews.end())
 
724
        d->_LpcPassivViews.remove(pcView);
 
725
    }
 
726
    else {
 
727
        if (find(d->_LpcViews.begin(),d->_LpcViews.end(),pcView)
 
728
            != d->_LpcViews.end())
 
729
        d->_LpcViews.remove(pcView);
 
730
 
 
731
        // last view?
 
732
        if (d->_LpcViews.size() == 0) {
 
733
            // decouple a passive view
 
734
            std::list<Gui::BaseView*>::iterator It = d->_LpcPassivViews.begin();
 
735
            while (It != d->_LpcPassivViews.end()) {
 
736
                (*It)->setDocument(0);
 
737
                It = d->_LpcPassivViews.begin();
 
738
            }
 
739
 
 
740
            // is already  closing the document
 
741
            if (d->_isClosing == false)
 
742
                d->_pcAppWnd->onLastWindowClosed(this);
 
743
        }
 
744
    }
 
745
}
 
746
 
 
747
void Document::onUpdate(void)
 
748
{
 
749
#ifdef FC_LOGUPDATECHAIN
 
750
    Base::Console().Log("Acti: Gui::Document::onUpdate()");
 
751
#endif
 
752
 
 
753
    std::list<Gui::BaseView*>::iterator It;
 
754
 
 
755
    for(It = d->_LpcViews.begin();It != d->_LpcViews.end();It++) {
 
756
        (*It)->onUpdate();
 
757
    }
 
758
 
 
759
    for(It = d->_LpcPassivViews.begin();It != d->_LpcPassivViews.end();It++) {
 
760
        (*It)->onUpdate();
 
761
    }
 
762
}
 
763
 
 
764
void Document::onRelabel(void)
 
765
{
 
766
#ifdef FC_LOGUPDATECHAIN
 
767
    Base::Console().Log("Acti: Gui::Document::onRelabel()");
 
768
#endif
 
769
 
 
770
    std::list<Gui::BaseView*>::iterator It;
 
771
 
 
772
    for (It = d->_LpcViews.begin();It != d->_LpcViews.end();It++) {
 
773
        (*It)->onRelabel(this);
 
774
    }
 
775
 
 
776
    for (It = d->_LpcPassivViews.begin();It != d->_LpcPassivViews.end();It++) {
 
777
        (*It)->onRelabel(this);
 
778
    }
 
779
}
 
780
 
 
781
bool Document::isLastView(void)
 
782
{
 
783
    if (d->_LpcViews.size() <= 1)
 
784
        return true;
 
785
    return false;
 
786
}
 
787
 
 
788
/** 
 
789
 *  This method checks if the document can be closed. It checks on
 
790
 *  the save state of the document and is able to abort the closing.
 
791
 */
 
792
bool Document::canClose ()
 
793
{
 
794
    if (!getDocument()->isClosable()) {
 
795
        QMessageBox::warning(getActiveView(),
 
796
            QObject::tr("Document not closable"),
 
797
            QObject::tr("The document is not closable for the moment."));
 
798
        return false;
 
799
    }
 
800
 
 
801
    if (!isModified())
 
802
        return true;
 
803
    bool ok = true;
 
804
    switch(QMessageBox::question(getActiveView(),
 
805
        QObject::tr("Unsaved document"),
 
806
        QObject::tr("Save document before close?"),
 
807
        QMessageBox::Yes | QMessageBox::Default,
 
808
        QMessageBox::No,
 
809
        QMessageBox::Cancel | QMessageBox::Escape))
 
810
    {
 
811
    case QMessageBox::Yes:
 
812
        ok = save();
 
813
        break;
 
814
    case QMessageBox::No:
 
815
        ok = true;
 
816
        break;
 
817
    case QMessageBox::Cancel:
 
818
        ok = false;
 
819
        break;
 
820
    }
 
821
 
 
822
    return ok;
 
823
}
 
824
 
 
825
std::list<MDIView*> Document::getMDIViews() const
 
826
{
 
827
    std::list<MDIView*> views;
 
828
    for (std::list<BaseView*>::const_iterator it = d->_LpcViews.begin();
 
829
         it != d->_LpcViews.end(); ++it) {
 
830
        MDIView* view = dynamic_cast<MDIView*>(*it);
 
831
        if (view)
 
832
            views.push_back(view);
 
833
    }
 
834
 
 
835
    return views;
 
836
}
 
837
 
 
838
/// send messages to the active view
 
839
bool Document::sendMsgToViews(const char* pMsg)
 
840
{
 
841
    std::list<Gui::BaseView*>::iterator It;
 
842
    const char** pReturnIgnore=0;
 
843
 
 
844
    for (It = d->_LpcViews.begin();It != d->_LpcViews.end();It++) {
 
845
        if ((*It)->onMsg(pMsg,pReturnIgnore)) {
 
846
            return true;
 
847
        }
 
848
    }
 
849
 
 
850
    for (It = d->_LpcPassivViews.begin();It != d->_LpcPassivViews.end();It++) {
 
851
        if ((*It)->onMsg(pMsg,pReturnIgnore)) {
 
852
            return true;
 
853
        }
 
854
    }
 
855
 
 
856
    return false;
 
857
}
 
858
 
 
859
/// Getter for the active view
 
860
MDIView* Document::getActiveView(void) const
 
861
{
 
862
    // get the main window's active view 
 
863
    MDIView* active = getMainWindow()->activeWindow();
 
864
 
 
865
    // get all MDI views of the document
 
866
    std::list<MDIView*> mdis = getMDIViews();
 
867
 
 
868
    // check whether the active view is part of this document
 
869
    bool ok=false;
 
870
    for (std::list<MDIView*>::const_iterator it = mdis.begin(); it != mdis.end(); ++it) {
 
871
        if ((*it) == active) {
 
872
            ok = true;
 
873
            break;
 
874
        }
 
875
    }
 
876
 
 
877
    // the active view is not part of this document, just use the first view
 
878
    if (!ok && !mdis.empty())
 
879
        active = mdis.front();
 
880
 
 
881
    return active;
 
882
}
 
883
 
 
884
 
 
885
//--------------------------------------------------------------------------
 
886
// UNDO REDO transaction handling  
 
887
//--------------------------------------------------------------------------
 
888
/** Open a new Undo transaction on the active document
 
889
 *  This method opens a new UNDO transaction on the active document. This transaction
 
890
 *  will later appear in the UNDO/REDO dialog with the name of the command. If the user 
 
891
 *  recall the transaction everything changed on the document between OpenCommand() and 
 
892
 *  CommitCommand will be undone (or redone). You can use an alternetive name for the 
 
893
 *  operation default is the command name.
 
894
 *  @see CommitCommand(),AbortCommand()
 
895
 */
 
896
void Document::openCommand(const char* sName)
 
897
{
 
898
    getDocument()->openTransaction(sName);
 
899
}
 
900
 
 
901
void Document::commitCommand(void)
 
902
{
 
903
    getDocument()->commitTransaction(); 
 
904
}
 
905
 
 
906
void Document::abortCommand(void)
 
907
{
 
908
    getDocument()->abortTransaction();  
 
909
}
 
910
 
 
911
/// Get a string vector with the 'Undo' actions
 
912
std::vector<std::string> Document::getUndoVector(void) const
 
913
{
 
914
    return getDocument()->getAvailableUndoNames();
 
915
}
 
916
 
 
917
/// Get a string vector with the 'Redo' actions
 
918
std::vector<std::string> Document::getRedoVector(void) const
 
919
{
 
920
    return getDocument()->getAvailableRedoNames();
 
921
}
 
922
 
 
923
/// Will UNDO  one or more steps
 
924
void Document::undo(int iSteps)
 
925
{
 
926
    for (int i=0;i<iSteps;i++) {
 
927
        getDocument()->undo();
 
928
    }
 
929
}
 
930
 
 
931
/// Will REDO  one or more steps
 
932
void Document::redo(int iSteps)
 
933
{
 
934
    for (int i=0;i<iSteps;i++) {
 
935
        getDocument()->redo();
 
936
    }
 
937
}
 
938
 
 
939
PyObject* Document::getPyObject(void)
 
940
{
 
941
    _pcDocPy->IncRef();
 
942
    return _pcDocPy;
 
943
}