DocumentModel.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2010 Werner Mayer <wmayer[at]users.sourceforge.net>     *
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>
00028 # include <algorithm>
00029 # include <boost/signals.hpp>
00030 # include <boost/bind.hpp>
00031 #endif
00032 
00033 #include "DocumentModel.h"
00034 #include "Application.h"
00035 #include "BitmapFactory.h"
00036 #include "Document.h"
00037 #include "ViewProviderDocumentObject.h"
00038 #include <App/Document.h>
00039 #include <App/DocumentObject.h>
00040 #include <App/PropertyLinks.h>
00041 
00042 using namespace Gui;
00043 
00044 namespace Gui {
00045     // forward declaration
00046     class ViewProviderIndex;
00047 
00048     // Base class
00049     class DocumentModelIndex : public Base::BaseClass
00050     {
00051         TYPESYSTEM_HEADER();
00052 
00053     public:
00054         virtual ~DocumentModelIndex()
00055         { qDeleteAll(childItems); }
00056 
00057         void reset()
00058         { qDeleteAll(childItems); childItems.clear(); }
00059         void setParent(DocumentModelIndex* parent)
00060         { parentItem = parent; }
00061         DocumentModelIndex *parent() const
00062         { return parentItem; }
00063         void appendChild(DocumentModelIndex *child)
00064         { childItems.append(child); child->setParent(this); }
00065         void removeChild(int row)
00066         { childItems.removeAt(row); }
00067 
00068         DocumentModelIndex *child(int row)
00069         { return childItems.value(row); }
00070         int row() const
00071         {
00072             if (parentItem)
00073                 return parentItem->childItems.indexOf
00074                     (const_cast<DocumentModelIndex*>(this));
00075             return 0;
00076         }
00077         int childCount() const
00078         { return childItems.count(); }
00079         virtual QVariant data(int role) const
00080         { return QVariant(); }
00081         virtual bool setData (const QVariant & value, int role)
00082         {
00083             if (role == Qt::EditRole) {
00084                 return true;
00085             }
00086 
00087             return true;
00088         }
00089         virtual Qt::ItemFlags flags() const
00090         {
00091             return Qt::ItemIsSelectable|Qt::ItemIsEnabled;
00092         }
00093 
00094     protected:
00095         DocumentModelIndex() : parentItem(0) {}
00096         DocumentModelIndex *parentItem;
00097         QList<DocumentModelIndex*> childItems;
00098     };
00099     // Root node
00100     class ApplicationIndex : public DocumentModelIndex
00101     {
00102         TYPESYSTEM_HEADER();
00103 
00104     public:
00105         ApplicationIndex(){}
00106         int findChild(const Gui::Document& d) const;
00107         Qt::ItemFlags flags() const
00108         { return Qt::ItemIsEnabled; }
00109         QVariant data(int role) const
00110         {
00111             if (role == Qt::DecorationRole) {
00112                 return qApp->windowIcon();
00113             }
00114             else if (role == Qt::DisplayRole) {
00115                 return DocumentModel::tr("Application");
00116             }
00117             return QVariant();
00118         }
00119     };
00120     // Document nodes
00121     class DocumentIndex : public DocumentModelIndex
00122     {
00123         TYPESYSTEM_HEADER();
00124         static QIcon* documentIcon;
00125 
00126     public:
00127         const Gui::Document& d;
00128         DocumentIndex(const Gui::Document& d) : d(d)
00129         {
00130             if (!documentIcon)
00131                 documentIcon = new QIcon(Gui::BitmapFactory().pixmap("Document"));
00132         }
00133         int findViewProvider(const ViewProvider&) const;
00134         void findViewProviders(const ViewProvider&, QList<ViewProviderIndex*>&) const;
00135         QVariant data(int role) const
00136         {
00137             if (role == Qt::DecorationRole) {
00138                 return *documentIcon;
00139             }
00140             else if (role == Qt::DisplayRole) {
00141                 App::Document* doc = d.getDocument();
00142                 return QString::fromUtf8(doc->Label.getValue());
00143             }
00144             else if (role == Qt::FontRole) {
00145                 Document* doc = Application::Instance->activeDocument();
00146                 QFont font;
00147                 font.setBold(doc==&d);
00148                 QVariant variant;
00149                 variant.setValue<QFont>(font);
00150                 return variant;
00151             }
00152 
00153             return QVariant();
00154         }
00155     };
00156 
00157     // Object nodes
00158     class ViewProviderIndex : public DocumentModelIndex
00159     {
00160         TYPESYSTEM_HEADER();
00161 
00162     public:
00163         const Gui::ViewProviderDocumentObject& v;
00164         ViewProviderIndex(const Gui::ViewProviderDocumentObject& v) : v(v){}
00165         void findViewProviders(const ViewProvider&, QList<ViewProviderIndex*>&) const;
00166         QVariant data(int role) const
00167         {
00168             if (role == Qt::DecorationRole) {
00169                 return v.getIcon();
00170             }
00171             else if (role == Qt::DisplayRole) {
00172                 App::DocumentObject* obj = v.getObject();
00173                 return QString::fromUtf8(obj->Label.getValue());
00174             }
00175             else if (role == Qt::FontRole) {
00176                 App::DocumentObject* obj = v.getObject();
00177                 App::DocumentObject* act = obj->getDocument()->getActiveObject();
00178                 QFont font;
00179                 font.setBold(obj==act);
00180                 QVariant variant;
00181                 variant.setValue<QFont>(font);
00182                 return variant;
00183             }
00184 
00185             return QVariant();
00186         }
00187     };
00188 
00189     int ApplicationIndex::findChild(const Gui::Document& d) const
00190     {
00191         int child=0;
00192         QList<DocumentModelIndex*>::const_iterator it;
00193         for (it = childItems.begin(); it != childItems.end(); ++it, ++child) {
00194             DocumentIndex* doc = static_cast<DocumentIndex*>(*it);
00195             if (&doc->d == &d)
00196                 return child;
00197         }
00198 
00199         return -1;
00200     }
00201 
00202     QIcon* DocumentIndex::documentIcon = 0;
00203 
00204     void DocumentIndex::findViewProviders(const ViewProvider& vp,
00205         QList<ViewProviderIndex*>& index) const
00206     {
00207         QList<DocumentModelIndex*>::const_iterator it;
00208         for (it = childItems.begin(); it != childItems.end(); ++it) {
00209             ViewProviderIndex* v = static_cast<ViewProviderIndex*>(*it);
00210             v->findViewProviders(vp, index);
00211         }
00212     }
00213 
00214     int DocumentIndex::findViewProvider(const ViewProvider& vp) const
00215     {
00216         QList<DocumentModelIndex*>::const_iterator it;
00217         int index=0;
00218         for (it = childItems.begin(); it != childItems.end(); ++it, ++index) {
00219             ViewProviderIndex* v = static_cast<ViewProviderIndex*>(*it);
00220             if (&v->v == &vp)
00221                 return index;
00222         }
00223 
00224         return -1;
00225     }
00226 
00227     void ViewProviderIndex::findViewProviders(const ViewProvider& vp,
00228         QList<ViewProviderIndex*>& index) const
00229     {
00230         if (&this->v == &vp)
00231             index.push_back(const_cast<ViewProviderIndex*>(this));
00232         QList<DocumentModelIndex*>::const_iterator it;
00233         for (it = childItems.begin(); it != childItems.end(); ++it) {
00234             ViewProviderIndex* v = static_cast<ViewProviderIndex*>(*it);
00235             v->findViewProviders(vp, index);
00236         }
00237     }
00238 
00239     TYPESYSTEM_SOURCE_ABSTRACT(Gui::DocumentModelIndex, Base::BaseClass);
00240     TYPESYSTEM_SOURCE_ABSTRACT(Gui::ApplicationIndex,Gui::DocumentModelIndex);
00241     TYPESYSTEM_SOURCE_ABSTRACT(Gui::DocumentIndex, Gui::DocumentModelIndex);
00242     TYPESYSTEM_SOURCE_ABSTRACT(Gui::ViewProviderIndex, Gui::DocumentModelIndex);
00243 
00244     struct DocumentModelP
00245     {
00246         DocumentModelP()
00247         { rootItem = new ApplicationIndex(); }
00248         ~DocumentModelP()
00249         { delete rootItem; }
00250         ApplicationIndex *rootItem;
00251     };
00252 }
00253 
00254 // -----------------------------------------------------------------
00255 
00256 DocumentModel::DocumentModel(QObject* parent)
00257     : QAbstractItemModel(parent), d(new DocumentModelP)
00258 {
00259     static bool inittype = false;
00260     if (!inittype) {
00261         inittype = true;
00262         DocumentModelIndex  ::init();
00263         ApplicationIndex    ::init();
00264         DocumentIndex       ::init();
00265         ViewProviderIndex   ::init();
00266     }
00267 
00268     // Setup connections
00269     Application::Instance->signalNewDocument.connect(boost::bind(&DocumentModel::slotNewDocument, this, _1));
00270     Application::Instance->signalDeleteDocument.connect(boost::bind(&DocumentModel::slotDeleteDocument, this, _1));
00271     Application::Instance->signalRenameDocument.connect(boost::bind(&DocumentModel::slotRenameDocument, this, _1));
00272     Application::Instance->signalActiveDocument.connect(boost::bind(&DocumentModel::slotActiveDocument, this, _1));
00273     Application::Instance->signalRelabelDocument.connect(boost::bind(&DocumentModel::slotRelabelDocument, this, _1));
00274 }
00275 
00276 DocumentModel::~DocumentModel()
00277 {
00278     delete d; d = 0;
00279 }
00280 
00281 void DocumentModel::slotNewDocument(const Gui::Document& Doc)
00282 {
00283     Doc.signalNewObject.connect(boost::bind(&DocumentModel::slotNewObject, this, _1));
00284     Doc.signalDeletedObject.connect(boost::bind(&DocumentModel::slotDeleteObject, this, _1));
00285     Doc.signalChangedObject.connect(boost::bind(&DocumentModel::slotChangeObject, this, _1, _2));
00286     Doc.signalRenamedObject.connect(boost::bind(&DocumentModel::slotRenameObject, this, _1));
00287     Doc.signalActivatedObject.connect(boost::bind(&DocumentModel::slotActiveObject, this, _1));
00288     Doc.signalInEdit.connect(boost::bind(&DocumentModel::slotInEdit, this, _1));
00289     Doc.signalResetEdit.connect(boost::bind(&DocumentModel::slotResetEdit, this, _1));
00290 
00291     QModelIndex parent = createIndex(0,0,d->rootItem);
00292     int count_docs = d->rootItem->childCount();
00293     beginInsertRows(parent, count_docs, count_docs);
00294     d->rootItem->appendChild(new DocumentIndex(Doc));
00295     endInsertRows();
00296 }
00297 
00298 void DocumentModel::slotDeleteDocument(const Gui::Document& Doc)
00299 {
00300     int row = d->rootItem->findChild(Doc);
00301     if (row > -1) {
00302         QModelIndex parent = createIndex(0,0,d->rootItem);
00303         beginRemoveRows(parent, row, row);
00304         DocumentModelIndex* item = d->rootItem->child(row);
00305         d->rootItem->removeChild(row);
00306         delete item;
00307         endRemoveRows();
00308     }
00309 }
00310 
00311 void DocumentModel::slotRenameDocument(const Gui::Document& Doc)
00312 {
00313     // do nothing here
00314 }
00315 
00316 void DocumentModel::slotRelabelDocument(const Gui::Document& Doc)
00317 {
00318     int row = d->rootItem->findChild(Doc);
00319     if (row > -1) {
00320         QModelIndex parent = createIndex(0,0,d->rootItem);
00321         QModelIndex item = index (row, 0, parent);
00322         dataChanged(item, item);
00323     }
00324 }
00325 
00326 void DocumentModel::slotActiveDocument(const Gui::Document& /*Doc*/)
00327 {
00328     // don't know which was the previous active document, so check simply all
00329     QModelIndex parent = createIndex(0,0,d->rootItem);
00330     QModelIndex top = index (0, 0, parent);
00331     QModelIndex bottom = index (d->rootItem->childCount()-1, 0, parent);
00332     dataChanged(top, bottom);
00333 }
00334 
00335 void DocumentModel::slotInEdit(const Gui::ViewProviderDocumentObject& v)
00336 {
00337 }
00338 
00339 void DocumentModel::slotResetEdit(const Gui::ViewProviderDocumentObject& v)
00340 {
00341 }
00342 
00343 void DocumentModel::slotNewObject(const Gui::ViewProviderDocumentObject& obj)
00344 {
00345     App::Document* doc = obj.getObject()->getDocument();
00346     Gui::Document* gdc = Application::Instance->getDocument(doc);
00347     int row = d->rootItem->findChild(*gdc);
00348     if (row > -1) {
00349         DocumentIndex* index = static_cast<DocumentIndex*>(d->rootItem->child(row));
00350         QModelIndex parent = createIndex(index->row(),0,index);
00351         int count_obj = index->childCount();
00352         beginInsertRows(parent, count_obj, count_obj);
00353         index->appendChild(new ViewProviderIndex(obj));
00354         endInsertRows();
00355     }
00356 }
00357 
00358 void DocumentModel::slotDeleteObject(const Gui::ViewProviderDocumentObject& obj)
00359 {
00360     App::Document* doc = obj.getObject()->getDocument();
00361     Gui::Document* gdc = Application::Instance->getDocument(doc);
00362     int row = d->rootItem->findChild(*gdc);
00363     if (row > -1) {
00364         DocumentIndex* doc_index = static_cast<DocumentIndex*>(d->rootItem->child(row));
00365         QList<ViewProviderIndex*> views;
00366         doc_index->findViewProviders(obj, views);
00367         for (QList<ViewProviderIndex*>::iterator it = views.begin(); it != views.end(); ++it) {
00368             DocumentModelIndex* parentitem = (*it)->parent();
00369             QModelIndex parent = createIndex(doc_index->row(), 0, parentitem);
00370             int row = (*it)->row();
00371             beginRemoveRows(parent, row, row);
00372             parentitem->removeChild(row);
00373             delete *it;
00374             endRemoveRows();
00375         }
00376     }
00377 }
00378 
00379 void DocumentModel::slotChangeObject(const Gui::ViewProviderDocumentObject& obj, const App::Property& Prop)
00380 {
00381     App::DocumentObject* fea = obj.getObject();
00382     if (&fea->Label == &Prop) {
00383         App::Document* doc = fea->getDocument();
00384         Gui::Document* gdc = Application::Instance->getDocument(doc);
00385         int row = d->rootItem->findChild(*gdc);
00386         if (row > -1) {
00387             DocumentIndex* doc_index = static_cast<DocumentIndex*>(d->rootItem->child(row));
00388             QList<ViewProviderIndex*> views;
00389             doc_index->findViewProviders(obj, views);
00390             for (QList<ViewProviderIndex*>::iterator it = views.begin(); it != views.end(); ++it) {
00391                 DocumentModelIndex* parentitem = (*it)->parent();
00392                 QModelIndex parent = createIndex(0,0,parentitem);
00393                 int row = (*it)->row();
00394                 QModelIndex item = index (row, 0, parent);
00395                 dataChanged(item, item);
00396             }
00397         }
00398     }
00399     else if (isPropertyLink(Prop)) {
00400         App::Document* doc = fea->getDocument();
00401         Gui::Document* gdc = Application::Instance->getDocument(doc);
00402         std::vector<ViewProviderDocumentObject*> views = getLinkedObjects(*gdc, Prop);
00403 
00404         int row = d->rootItem->findChild(*gdc);
00405         if (row > -1) {
00406             DocumentIndex* doc_index = static_cast<DocumentIndex*>(d->rootItem->child(row));
00407             QList<ViewProviderIndex*> obj_index;
00408             doc_index->findViewProviders(obj, obj_index);
00409 
00410             // remove from top level in document
00411             for (std::vector<ViewProviderDocumentObject*>::iterator vp = views.begin(); vp != views.end(); ++vp) {
00412                 int row = doc_index->findViewProvider(**vp);
00413                 if (row >= 0) {
00414                     DocumentModelIndex* child = doc_index->child(row);
00415                     QModelIndex parent = createIndex(doc_index->row(), 0, doc_index);
00416                     beginRemoveRows(parent, row, row);
00417                     doc_index->removeChild(row);
00418                     delete child;
00419                     endRemoveRows();
00420                 }
00421             }
00422 
00423             for (QList<ViewProviderIndex*>::iterator it = obj_index.begin(); it != obj_index.end(); ++it) {
00424                 QModelIndex parent = createIndex((*it)->row(),0,*it);
00425                 int count_obj = (*it)->childCount();
00426                 beginInsertRows(parent, count_obj, count_obj + (int)views.size());
00427                 for (std::vector<ViewProviderDocumentObject*>::iterator jt = views.begin(); jt != views.end(); ++jt)
00428                     (*it)->appendChild(new ViewProviderIndex(**jt));
00429                 endInsertRows();
00430             }
00431         }
00432     }
00433 }
00434 
00435 void DocumentModel::slotRenameObject(const Gui::ViewProviderDocumentObject& obj)
00436 {
00437     // renaming of objects not supported at the moment
00438 }
00439 
00440 void DocumentModel::slotActiveObject(const Gui::ViewProviderDocumentObject& obj)
00441 {
00442     // do nothing here because this is automatically done by calling
00443     // ViewProviderIndex::data()
00444 }
00445 
00446 const Document* DocumentModel::getDocument(const QModelIndex& index) const
00447 {
00448     if (!index.isValid())
00449         return 0;
00450     Base::BaseClass* item = 0;
00451     item = static_cast<Base::BaseClass*>(index.internalPointer());
00452     if (item->getTypeId() == DocumentIndex::getClassTypeId()) {
00453         const Gui::Document& d = static_cast<DocumentIndex*>(item)->d;
00454         return (&d);
00455     }
00456 
00457     return 0;
00458 }
00459 
00460 bool DocumentModel::isPropertyLink(const App::Property& prop) const
00461 {
00462     if (prop.isDerivedFrom(App::PropertyLink::getClassTypeId()))
00463         return true;
00464     if (prop.isDerivedFrom(App::PropertyLinkList::getClassTypeId()))
00465         return true;
00466     return false;
00467 }
00468 
00469 std::vector<ViewProviderDocumentObject*>
00470 DocumentModel::getLinkedObjects(const Gui::Document& doc, const App::Property& prop) const
00471 {
00472     std::vector<ViewProviderDocumentObject*> links;
00473     if (prop.isDerivedFrom(App::PropertyLink::getClassTypeId())) {
00474         App::DocumentObject* obj;
00475         obj = static_cast<const App::PropertyLink&>(prop).getValue();
00476         ViewProvider* view = doc.getViewProvider(obj);
00477         if (view && view->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
00478             links.push_back(static_cast<ViewProviderDocumentObject*>(view));
00479     }
00480     else if (prop.isDerivedFrom(App::PropertyLinkList::getClassTypeId())) {
00481         const std::vector<App::DocumentObject*>& refs = static_cast
00482             <const App::PropertyLinkList&>(prop).getValues();
00483         for (std::vector<App::DocumentObject*>::const_iterator it = refs.begin();it != refs.end(); ++it) {
00484             ViewProvider* view = doc.getViewProvider(*it);
00485             if (view && view->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
00486                 links.push_back(static_cast<ViewProviderDocumentObject*>(view));
00487         }
00488     }
00489 
00490     return links;
00491 }
00492 
00493 int DocumentModel::columnCount (const QModelIndex & /*parent*/) const
00494 {
00495     return 1;
00496 }
00497 
00498 QVariant DocumentModel::data (const QModelIndex & index, int role) const
00499 {
00500     if (!index.isValid())
00501         return QVariant();
00502     return static_cast<DocumentModelIndex*>(index.internalPointer())->data(role);
00503 }
00504 
00505 bool DocumentModel::setData(const QModelIndex& index, const QVariant & value, int role)
00506 {
00507     if (!index.isValid())
00508         return false;
00509     return static_cast<DocumentModelIndex*>(index.internalPointer())->setData(value, role);
00510 }
00511 
00512 Qt::ItemFlags DocumentModel::flags(const QModelIndex &index) const
00513 {
00514     //if (index.internalPointer() == d->rootItem)
00515     //    return Qt::ItemIsEnabled;
00516     //return QAbstractItemModel::flags(index);
00517     if (!index.isValid())
00518         return 0;
00519     return static_cast<DocumentModelIndex*>(index.internalPointer())->flags();
00520 }
00521 
00522 QModelIndex DocumentModel::index (int row, int column, const QModelIndex & parent) const
00523 {
00524     DocumentModelIndex* item = 0;
00525     if (!parent.isValid())
00526         item = d->rootItem;
00527     else
00528         item = static_cast<DocumentModelIndex*>(parent.internalPointer())->child(row);
00529     if (!item)
00530         return QModelIndex();
00531     return createIndex(row, column, item);
00532 }
00533 
00534 QModelIndex DocumentModel::parent (const QModelIndex & index) const
00535 {
00536     if (!index.isValid() || index.internalPointer() == d->rootItem)
00537         return QModelIndex();
00538     DocumentModelIndex* item = 0;
00539     item = static_cast<DocumentModelIndex*>(index.internalPointer());
00540     DocumentModelIndex* parent = item->parent();
00541     return createIndex(parent->row(), 0, parent);
00542 }
00543 
00544 int DocumentModel::rowCount (const QModelIndex & parent) const
00545 {
00546     if (!parent.isValid())
00547         return 1; // the root item
00548     DocumentModelIndex* item = 0;
00549     item = static_cast<DocumentModelIndex*>(parent.internalPointer());
00550     return item->childCount();
00551 }
00552 
00553 QVariant DocumentModel::headerData (int section, Qt::Orientation orientation, int role) const
00554 {
00555     if (orientation == Qt::Horizontal) {
00556         if (role != Qt::DisplayRole)
00557             return QVariant();
00558         return tr("Labels & Attributes");
00559     }
00560 
00561     return QVariant();
00562 }
00563 
00564 bool DocumentModel::setHeaderData (int, Qt::Orientation, const QVariant &, int)
00565 {
00566     return false;
00567 }

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