Gui/Tree.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 <boost/signals.hpp>
00028 # include <boost/bind.hpp>
00029 # include <QAction>
00030 # include <QActionGroup>
00031 # include <QApplication>
00032 # include <qcursor.h>
00033 # include <qlayout.h>
00034 # include <qstatusbar.h>
00035 # include <QContextMenuEvent>
00036 # include <QMenu>
00037 # include <QPixmap>
00038 # include <QTimer>
00039 #endif
00040 
00041 #include <Base/Console.h>
00042 #include <App/Document.h>
00043 #include <App/DocumentObject.h>
00044 #include <App/DocumentObjectGroup.h>
00045 
00046 #include "Tree.h"
00047 #include "Document.h"
00048 #include "BitmapFactory.h"
00049 #include "ViewProviderDocumentObject.h"
00050 #include "MenuManager.h"
00051 #include "Application.h"
00052 #include "MainWindow.h"
00053 
00054 using namespace Gui;
00055 
00056 QPixmap*  TreeWidget::documentPixmap = 0;
00057 const int TreeWidget::DocumentType = 1000;
00058 const int TreeWidget::ObjectType = 1001;
00059 
00060 
00061 /* TRANSLATOR Gui::TreeWidget */
00062 TreeWidget::TreeWidget(QWidget* parent)
00063     : QTreeWidget(parent), fromOutside(false)
00064 {
00065     this->setDragEnabled(true);
00066     this->setAcceptDrops(true);
00067     this->setDropIndicatorShown(false);
00068     this->setRootIsDecorated(false);
00069 
00070     this->createGroupAction = new QAction(this);
00071     this->createGroupAction->setText(tr("Create group..."));
00072     this->createGroupAction->setStatusTip(tr("Create a group"));
00073     connect(this->createGroupAction, SIGNAL(triggered()),
00074             this, SLOT(onCreateGroup()));
00075     this->relabelObjectAction = new QAction(this);
00076     this->relabelObjectAction->setText(tr("Rename"));
00077     this->relabelObjectAction->setStatusTip(tr("Rename object"));
00078     this->relabelObjectAction->setShortcut(Qt::Key_F2);
00079     connect(this->relabelObjectAction, SIGNAL(triggered()),
00080             this, SLOT(onRelabelObject()));
00081     this->finishEditingAction = new QAction(this);
00082     this->finishEditingAction->setText(tr("Finish editing"));
00083     this->finishEditingAction->setStatusTip(tr("Finish editing object"));
00084     connect(this->finishEditingAction, SIGNAL(triggered()),
00085             this, SLOT(onFinishEditing()));
00086 
00087     // Setup connections
00088     Application::Instance->signalNewDocument.connect(boost::bind(&TreeWidget::slotNewDocument, this, _1));
00089     Application::Instance->signalDeleteDocument.connect(boost::bind(&TreeWidget::slotDeleteDocument, this, _1));
00090     Application::Instance->signalRenameDocument.connect(boost::bind(&TreeWidget::slotRenameDocument, this, _1));
00091     Application::Instance->signalActiveDocument.connect(boost::bind(&TreeWidget::slotActiveDocument, this, _1));
00092     Application::Instance->signalRelabelDocument.connect(boost::bind(&TreeWidget::slotRelabelDocument, this, _1));
00093 
00094     QStringList labels;
00095     labels << tr("Labels & Attributes");
00096     this->setHeaderLabels(labels);
00097 
00098     // Add the first main label
00099     this->rootItem = new QTreeWidgetItem(this);
00100     this->rootItem->setText(0, tr("Application"));
00101     this->rootItem->setFlags(Qt::ItemIsEnabled);
00102     this->expandItem(this->rootItem);
00103     this->setSelectionMode(QAbstractItemView::ExtendedSelection);
00104 #if QT_VERSION >= 0x040200
00105     // causes unexpected drop events (possibly only with Qt4.1.x)
00106     this->setMouseTracking(true); // needed for itemEntered() to work
00107 #endif
00108 
00109     this->statusTimer = new QTimer(this);
00110 
00111     connect(this->statusTimer, SIGNAL(timeout()), 
00112             this, SLOT(onTestStatus()));
00113     connect(this, SIGNAL(itemEntered(QTreeWidgetItem*, int)),
00114             this, SLOT(onItemEntered(QTreeWidgetItem*)));
00115     connect(this, SIGNAL(itemSelectionChanged()),
00116             this, SLOT(onItemSelectionChanged()));
00117 
00118     this->statusTimer->setSingleShot(true);
00119     this->statusTimer->start(300);
00120     documentPixmap = new QPixmap(Gui::BitmapFactory().pixmap("Document"));
00121 }
00122 
00123 TreeWidget::~TreeWidget()
00124 {
00125 }
00126 
00127 void TreeWidget::contextMenuEvent (QContextMenuEvent * e)
00128 {
00129     // ask workbenches and view provider, ...
00130     MenuItem view;
00131     Gui::Application::Instance->setupContextMenu("Tree", &view);
00132 
00133     QMenu contextMenu;
00134     QMenu subMenu;
00135     QMenu editMenu;
00136     QActionGroup subMenuGroup(&subMenu);
00137     subMenuGroup.setExclusive(true);
00138     connect(&subMenuGroup, SIGNAL(triggered(QAction*)),
00139             this, SLOT(onActivateDocument(QAction*)));
00140     MenuManager::getInstance()->setupContextMenu(&view, contextMenu);
00141 
00142     // get the current item
00143     this->contextItem = itemAt(e->pos());
00144     if (this->contextItem && this->contextItem->type() == DocumentType) {
00145         if (!contextMenu.actions().isEmpty())
00146             contextMenu.addSeparator();
00147         contextMenu.addAction(this->createGroupAction);
00148     }
00149     else if (this->contextItem && this->contextItem->type() == ObjectType) {
00150         DocumentObjectItem* objitem = static_cast<DocumentObjectItem*>
00151             (this->contextItem);
00152         if (objitem->object()->getObject()->isDerivedFrom(App::DocumentObjectGroup
00153             ::getClassTypeId())) {
00154             QList<QAction*> acts = contextMenu.actions();
00155             if (!acts.isEmpty()) {
00156                 QAction* first = acts.front();
00157                 QAction* sep = contextMenu.insertSeparator(first);
00158                 contextMenu.insertAction(sep, this->createGroupAction);
00159             }
00160             else
00161                 contextMenu.addAction(this->createGroupAction);
00162         }
00163         if (!contextMenu.actions().isEmpty())
00164             contextMenu.addSeparator();
00165         contextMenu.addAction(this->relabelObjectAction);
00166 
00167         // if only one item is selected setup the edit menu
00168         if (this->selectedItems().size() == 1) {
00169             objitem->object()->setupContextMenu(&editMenu, this, SLOT(onStartEditing()));
00170             QList<QAction*> editAct = editMenu.actions();
00171             if (!editAct.isEmpty()) {
00172                 QAction* topact = contextMenu.actions().front();
00173                 for (QList<QAction*>::iterator it = editAct.begin(); it != editAct.end(); ++it)
00174                     contextMenu.insertAction(topact, *it);
00175                 QAction* first = editAct.front();
00176                 contextMenu.setDefaultAction(first);
00177                 if (objitem->object()->isEditing())
00178                     contextMenu.insertAction(topact, this->finishEditingAction);
00179                 contextMenu.insertSeparator(topact);
00180             }
00181         }
00182     }
00183 
00184     // add a submenu to active a document if two or more exist
00185     std::vector<App::Document*> docs = App::GetApplication().getDocuments();
00186     if (docs.size() >= 2) {
00187         App::Document* activeDoc = App::GetApplication().getActiveDocument();
00188         subMenu.setTitle(tr("Activate document"));
00189         contextMenu.addMenu(&subMenu);
00190         QAction* active = 0;
00191         for (std::vector<App::Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
00192             QString label = QString::fromUtf8((*it)->Label.getValue());
00193             QAction* action = subMenuGroup.addAction(label);
00194             action->setCheckable(true);
00195             action->setStatusTip(tr("Activate document %1").arg(label));
00196             action->setData(QByteArray((*it)->getName()));
00197             if (*it == activeDoc) active = action;
00198         }
00199         if (active) active->setChecked(true);
00200         active = subMenuGroup.checkedAction();
00201         subMenu.addActions(subMenuGroup.actions());
00202     }
00203     if (contextMenu.actions().count() > 0)
00204         contextMenu.exec(QCursor::pos());
00205 }
00206 
00207 void TreeWidget::onCreateGroup()
00208 {
00209     QString name = tr("Group");
00210     if (this->contextItem->type() == DocumentType) {
00211         DocumentItem* docitem = static_cast<DocumentItem*>(this->contextItem);
00212         App::Document* doc = docitem->document()->getDocument();
00213         QString cmd = QString::fromAscii("App.getDocument(\"%1\").addObject"
00214                               "(\"App::DocumentObjectGroup\",\"%2\")")
00215                               .arg(QString::fromAscii(doc->getName())).arg(name);
00216         Gui::Document* gui = Gui::Application::Instance->getDocument(doc);
00217         gui->openCommand("Create group");
00218         Gui::Application::Instance->runPythonCode(cmd.toUtf8());
00219         gui->commitCommand();
00220     }
00221     else if (this->contextItem->type() == ObjectType) {
00222         DocumentObjectItem* objitem = static_cast<DocumentObjectItem*>
00223             (this->contextItem);
00224         App::DocumentObject* obj = objitem->object()->getObject();
00225         App::Document* doc = obj->getDocument();
00226         QString cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\")"
00227                               ".newObject(\"App::DocumentObjectGroup\",\"%3\")")
00228                               .arg(QString::fromAscii(doc->getName()))
00229                               .arg(QString::fromAscii(obj->getNameInDocument()))
00230                               .arg(name);
00231         Gui::Document* gui = Gui::Application::Instance->getDocument(doc);
00232         gui->openCommand("Create group");
00233         Gui::Application::Instance->runPythonCode(cmd.toUtf8());
00234         gui->commitCommand();
00235     }
00236 }
00237 
00238 void TreeWidget::onRelabelObject()
00239 {
00240     QTreeWidgetItem* item = currentItem();
00241     if (item)
00242         editItem(item);
00243 }
00244 
00245 void TreeWidget::onStartEditing()
00246 {
00247     QAction* action = qobject_cast<QAction*>(sender());
00248     if (action) {
00249         if (this->contextItem && this->contextItem->type() == ObjectType) {
00250             DocumentObjectItem* objitem = static_cast<DocumentObjectItem*>
00251                 (this->contextItem);
00252             int edit = action->data().toInt();
00253             App::DocumentObject* obj = objitem->object()->getObject();
00254             if (!obj) return;
00255             Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
00256             doc->setEdit(objitem->object(), edit);
00257         }
00258     }
00259 }
00260 
00261 void TreeWidget::onFinishEditing()
00262 {
00263     if (this->contextItem && this->contextItem->type() == ObjectType) {
00264         DocumentObjectItem* objitem = static_cast<DocumentObjectItem*>
00265             (this->contextItem);
00266         App::DocumentObject* obj = objitem->object()->getObject();
00267         if (!obj) return;
00268         Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument());
00269         doc->resetEdit();
00270         doc->getDocument()->recompute();
00271     }
00272 }
00273 
00274 void TreeWidget::onActivateDocument(QAction* active)
00275 {
00276     // activate the specified document
00277     QByteArray docname = active->data().toByteArray();
00278     Gui::Document* doc = Application::Instance->getDocument((const char*)docname);
00279     if (!doc) return;
00280     MDIView *view = doc->getActiveView();
00281     if (!view) return;
00282     getMainWindow()->setActiveWindow(view);
00283 }
00284 
00285 bool TreeWidget::dropMimeData(QTreeWidgetItem *parent, int index,
00286                               const QMimeData *data, Qt::DropAction action)
00287 {
00288     return QTreeWidget::dropMimeData(parent, index, data, action);
00289 }
00290 
00291 Qt::DropActions TreeWidget::supportedDropActions () const
00292 {
00293     return QTreeWidget::supportedDropActions();
00294 }
00295 
00296 void TreeWidget::mouseDoubleClickEvent (QMouseEvent * event)
00297 {
00298     QTreeWidgetItem* item = itemAt(event->pos());
00299     if (!item) return;
00300     if (item->type() == TreeWidget::DocumentType) {
00301         //QTreeWidget::mouseDoubleClickEvent(event);
00302         const Gui::Document* doc = static_cast<DocumentItem*>(item)->document();
00303         if (!doc) return;
00304         MDIView *view = doc->getActiveView();
00305         if (!view) return;
00306         getMainWindow()->setActiveWindow(view);
00307     }
00308     else if (item->type() == TreeWidget::ObjectType) {
00309         if (!(static_cast<DocumentObjectItem*>(item)->object())->doubleClicked())
00310             QTreeWidget::mouseDoubleClickEvent(event);
00311     }
00312 }
00313 
00314 QMimeData * TreeWidget::mimeData (const QList<QTreeWidgetItem *> items) const
00315 {
00316     // all selected items must reference an object from the same document
00317     App::Document* doc=0;
00318     for (QList<QTreeWidgetItem *>::ConstIterator it = items.begin(); it != items.end(); ++it) {
00319         if ((*it)->type() != TreeWidget::ObjectType)
00320             return 0;
00321         App::DocumentObject* obj = static_cast<DocumentObjectItem *>(*it)->object()->getObject();
00322         if (!doc)
00323             doc = obj->getDocument();
00324         else if (doc != obj->getDocument())
00325             return 0;
00326     }
00327     return QTreeWidget::mimeData(items);
00328 }
00329 
00330 void TreeWidget::dragMoveEvent(QDragMoveEvent *event)
00331 {
00332     QTreeWidget::dragMoveEvent(event);
00333     if (!event->isAccepted())
00334         return;
00335 
00336     QTreeWidgetItem* targetitem = itemAt(event->pos());
00337     if (!targetitem || this->isItemSelected(targetitem)) {
00338         event->ignore();
00339     }
00340     else if (targetitem->type() == TreeWidget::DocumentType) {
00341         QList<QModelIndex> idxs = selectedIndexes();
00342         App::Document* doc = static_cast<DocumentItem*>(targetitem)->
00343             document()->getDocument();
00344         for (QList<QModelIndex>::Iterator it = idxs.begin(); it != idxs.end(); ++it) {
00345             QTreeWidgetItem* item = itemFromIndex(*it);
00346             if (item->type() != TreeWidget::ObjectType) {
00347                 event->ignore();
00348                 return;
00349             }
00350             App::DocumentObject* obj = static_cast<DocumentObjectItem*>(item)->
00351                 object()->getObject();
00352             if (doc != obj->getDocument()) {
00353                 event->ignore();
00354                 return;
00355             }
00356         }
00357     }
00358     else if (targetitem->type() == TreeWidget::ObjectType) {
00359         App::DocumentObject* grp = static_cast<DocumentObjectItem*>(targetitem)->
00360             object()->getObject();
00361         if (!grp->getTypeId().isDerivedFrom(App::DocumentObjectGroup::
00362             getClassTypeId()))
00363             event->ignore();
00364         App::Document* doc = grp->getDocument();
00365         QList<QModelIndex> idxs = selectedIndexes();
00366         for (QList<QModelIndex>::Iterator it = idxs.begin(); it != idxs.end(); ++it) {
00367             QTreeWidgetItem* item = itemFromIndex(*it);
00368             if (item->type() != TreeWidget::ObjectType) {
00369                 event->ignore();
00370                 return;
00371             }
00372             App::DocumentObject* obj = static_cast<DocumentObjectItem*>(item)->
00373                 object()->getObject();
00374             if (doc != obj->getDocument()) {
00375                 event->ignore();
00376                 return;
00377             }
00378             if (obj->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId())) {
00379                 if (static_cast<App::DocumentObjectGroup*>(grp)->isChildOf(
00380                     static_cast<App::DocumentObjectGroup*>(obj))) {
00381                     event->ignore();
00382                     return;
00383                 }
00384             }
00385         }
00386     }
00387     else {
00388         event->ignore();
00389     }
00390 }
00391 
00392 void TreeWidget::dropEvent(QDropEvent *event)
00393 {
00394     QTreeWidgetItem* targetitem = itemAt(event->pos());
00395     // not dropped onto an item
00396     if (!targetitem)
00397         return;
00398     // one of the source items is also the destination item, that's not allowed
00399     if (this->isItemSelected(targetitem))
00400         return;
00401     
00402     // filter out the selected items we cannot handle
00403     QList<QTreeWidgetItem*> items;
00404     QList<QModelIndex> idxs = selectedIndexes();
00405     for (QList<QModelIndex>::Iterator it = idxs.begin(); it != idxs.end(); ++it) {
00406         QTreeWidgetItem* item = itemFromIndex(*it);
00407         if (item == targetitem)
00408             continue;
00409         if (item->parent() == targetitem)
00410             continue;
00411         items.push_back(item);
00412     }
00413 
00414     if (items.isEmpty())
00415         return; // nothing needs to be done
00416 
00417     if (targetitem->type() == TreeWidget::ObjectType) {
00418         // add object to group
00419         App::DocumentObject* grp = static_cast<DocumentObjectItem*>(targetitem)
00420             ->object()->getObject();
00421         if (!grp->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId()))
00422             return; // no group object
00423 
00424         // Open command
00425         App::Document* doc = grp->getDocument();
00426         Gui::Document* gui = Gui::Application::Instance->getDocument(doc);
00427         gui->openCommand("Move object");
00428         for (QList<QTreeWidgetItem*>::Iterator it = items.begin(); it != items.end(); ++it) {
00429             // get document object
00430             App::DocumentObject* obj = static_cast<DocumentObjectItem*>(*it)
00431                 ->object()->getObject();
00432             App::DocumentObjectGroup* par = App::DocumentObjectGroup
00433                 ::getGroupOfObject(obj);
00434             if (par) {
00435                 // allow an object to be in one group only
00436                 QString cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").removeObject("
00437                                       "App.getDocument(\"%1\").getObject(\"%3\"))")
00438                                       .arg(QString::fromAscii(doc->getName()))
00439                                       .arg(QString::fromAscii(par->getNameInDocument()))
00440                                       .arg(QString::fromAscii(obj->getNameInDocument()));
00441                 Gui::Application::Instance->runPythonCode(cmd.toUtf8());
00442             }
00443 
00444             // build Python command for execution
00445             QString cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").addObject("
00446                                   "App.getDocument(\"%1\").getObject(\"%3\"))")
00447                                   .arg(QString::fromAscii(doc->getName()))
00448                                   .arg(QString::fromAscii(grp->getNameInDocument()))
00449                                   .arg(QString::fromAscii(obj->getNameInDocument()));
00450             Gui::Application::Instance->runPythonCode(cmd.toUtf8());
00451         }
00452         gui->commitCommand();
00453     }
00454     else if (targetitem->type() == TreeWidget::DocumentType) {
00455         // Open command
00456         App::Document* doc = static_cast<DocumentItem*>(targetitem)->document()->getDocument();
00457         Gui::Document* gui = Gui::Application::Instance->getDocument(doc);
00458         gui->openCommand("Move object");
00459         for (QList<QTreeWidgetItem*>::Iterator it = items.begin(); it != items.end(); ++it) {
00460             // get document object
00461             // there must be a group that references this object
00462             App::DocumentObject* obj = static_cast<DocumentObjectItem*>(*it)
00463                 ->object()->getObject();
00464             App::DocumentObjectGroup* grp = App::DocumentObjectGroup
00465                 ::getGroupOfObject(obj);
00466             if (grp) {
00467                 QString cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").removeObject("
00468                                       "App.getDocument(\"%1\").getObject(\"%3\"))")
00469                                       .arg(QString::fromAscii(doc->getName()))
00470                                       .arg(QString::fromAscii(grp->getNameInDocument()))
00471                                       .arg(QString::fromAscii(obj->getNameInDocument()));
00472                 Gui::Application::Instance->runPythonCode(cmd.toUtf8());
00473             }
00474         }
00475         gui->commitCommand();
00476     }
00477 }
00478 
00479 void TreeWidget::drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const
00480 {
00481     QTreeWidget::drawRow(painter, options, index);
00482     // Set the text and highlighted text color of a hidden object to a dark
00483     //QTreeWidgetItem * item = itemFromIndex(index);
00484     //if (item->type() == ObjectType && !(static_cast<DocumentObjectItem*>(item)->previousStatus & 1)) {
00485     //    QStyleOptionViewItem opt(options);
00486     //    opt.state ^= QStyle::State_Enabled;
00487     //    QColor c = opt.palette.color(QPalette::Inactive, QPalette::Dark);
00488     //    opt.palette.setColor(QPalette::Inactive, QPalette::Text, c);
00489     //    opt.palette.setColor(QPalette::Inactive, QPalette::HighlightedText, c);
00490     //    QTreeWidget::drawRow(painter, opt, index);
00491     //}
00492     //else {
00493     //    QTreeWidget::drawRow(painter, options, index);
00494     //}
00495 }
00496 
00497 void TreeWidget::slotNewDocument(const Gui::Document& Doc)
00498 {
00499     DocumentItem* item = new DocumentItem(&Doc, this->rootItem);
00500     this->expandItem(item);
00501     item->setIcon(0, *documentPixmap);
00502     item->setText(0, QString::fromUtf8(Doc.getDocument()->Label.getValue()));
00503     DocumentMap[ &Doc ] = item;
00504 }
00505 
00506 void TreeWidget::slotDeleteDocument(const Gui::Document& Doc)
00507 {
00508     std::map<const Gui::Document*, DocumentItem*>::iterator it = DocumentMap.find(&Doc);
00509     if (it != DocumentMap.end()) {
00510         this->rootItem->takeChild(this->rootItem->indexOfChild(it->second));
00511         delete it->second;
00512         DocumentMap.erase(it);
00513     }
00514 }
00515 
00516 void TreeWidget::slotRenameDocument(const Gui::Document& Doc)
00517 {
00518     // do nothing here
00519 }
00520 
00521 void TreeWidget::slotRelabelDocument(const Gui::Document& Doc)
00522 {
00523     std::map<const Gui::Document*, DocumentItem*>::iterator it = DocumentMap.find(&Doc);
00524     if (it != DocumentMap.end()) {
00525         it->second->setText(0, QString::fromUtf8(Doc.getDocument()->Label.getValue()));
00526     }
00527 }
00528 
00529 void TreeWidget::slotActiveDocument(const Gui::Document& Doc)
00530 {
00531     std::map<const Gui::Document*, DocumentItem*>::iterator jt = DocumentMap.find(&Doc);
00532     if (jt == DocumentMap.end())
00533         return; // signal is emitted before the item gets created
00534     for (std::map<const Gui::Document*, DocumentItem*>::iterator it = DocumentMap.begin();
00535          it != DocumentMap.end(); ++it)
00536     {
00537         QFont f = it->second->font(0);
00538         f.setBold(it == jt);
00539         it->second->setFont(0,f);
00540     }
00541 }
00542 
00543 void TreeWidget::onTestStatus(void)
00544 {
00545     if (isVisible()) {
00546         std::map<const Gui::Document*,DocumentItem*>::iterator pos;
00547         for (pos = DocumentMap.begin();pos!=DocumentMap.end();++pos) {
00548             pos->second->testStatus();
00549         }
00550     }
00551 
00552     this->statusTimer->setSingleShot(true);
00553     this->statusTimer->start(300);
00554 }
00555 
00556 void TreeWidget::onItemEntered(QTreeWidgetItem * item)
00557 {
00558     // object item selected
00559     if ( item && item->type() == TreeWidget::ObjectType ) {
00560         DocumentObjectItem* obj = static_cast<DocumentObjectItem*>(item);
00561         obj->displayStatusInfo();
00562     }
00563 }
00564 
00565 void TreeWidget::scrollItemToTop(Gui::Document* doc)
00566 {
00567     std::map<const Gui::Document*,DocumentItem*>::iterator it;
00568     it = DocumentMap.find(doc);
00569     if (it != DocumentMap.end()) {
00570         DocumentItem* root = it->second;
00571         QTreeWidgetItemIterator it(root, QTreeWidgetItemIterator::Selected);
00572         for (; *it; ++it) {
00573             if ((*it)->type() == TreeWidget::ObjectType) {
00574                 this->scrollToItem(*it, QAbstractItemView::PositionAtTop);
00575                 break;
00576             }
00577         }
00578     }
00579 }
00580 
00581 void TreeWidget::changeEvent(QEvent *e)
00582 {
00583     if (e->type() == QEvent::LanguageChange) {
00584         this->headerItem()->setText(0, tr("Labels & Attributes"));
00585         this->rootItem->setText(0, tr("Application"));
00586     }
00587 
00588     QTreeWidget::changeEvent(e);
00589 }
00590 
00591 void TreeWidget::onItemSelectionChanged ()
00592 {
00593     // we already got notified by the selection to update the tree items
00594     if (this->isConnectionBlocked())
00595         return;
00596 
00597     // block tmp. the connection to avoid to notify us ourself
00598     bool lock = this->blockConnection(true);
00599     std::map<const Gui::Document*,DocumentItem*>::iterator pos;
00600     for (pos = DocumentMap.begin();pos!=DocumentMap.end();++pos) {
00601         pos->second->updateSelection();
00602     }
00603     this->blockConnection(lock);
00604 }
00605 
00606 void TreeWidget::onSelectionChanged(const SelectionChanges& msg)
00607 {
00608     switch (msg.Type)
00609     {
00610     case SelectionChanges::AddSelection:
00611         {
00612             Gui::Document* pDoc = Application::Instance->getDocument(msg.pDocName);
00613             std::map<const Gui::Document*, DocumentItem*>::iterator it;
00614             it = DocumentMap.find(pDoc);
00615             bool lock = this->blockConnection(true);
00616             if (it!= DocumentMap.end())
00617                 it->second->setObjectSelected(msg.pObjectName,true);
00618             this->blockConnection(lock);
00619         }   break;
00620     case SelectionChanges::RmvSelection:
00621         {
00622             Gui::Document* pDoc = Application::Instance->getDocument(msg.pDocName);
00623             std::map<const Gui::Document*, DocumentItem*>::iterator it;
00624             it = DocumentMap.find(pDoc);
00625             bool lock = this->blockConnection(true);
00626             if (it!= DocumentMap.end())
00627                 it->second->setObjectSelected(msg.pObjectName,false);
00628             this->blockConnection(lock);
00629         }   break;
00630     case SelectionChanges::SetSelection:
00631         {
00632             Gui::Document* pDoc = Application::Instance->getDocument(msg.pDocName);
00633             std::map<const Gui::Document*, DocumentItem*>::iterator it;
00634             it = DocumentMap.find(pDoc);
00635             // we get notified from the selection and must only update the selection on the tree,
00636             // thus no need to notify again the selection. See also onItemSelectionChanged().
00637             if (it != DocumentMap.end()) {
00638                 bool lock = this->blockConnection(true);
00639                 it->second->selectItems();
00640                 this->blockConnection(lock);
00641             }
00642         }   break;
00643     case SelectionChanges::ClrSelection:
00644         {
00645             // clears the complete selection
00646             if (strcmp(msg.pDocName,"") == 0) {
00647                 this->clearSelection ();
00648             }
00649             else {
00650                 // clears the selection of the given document
00651                 Gui::Document* pDoc = Application::Instance->getDocument(msg.pDocName);
00652                 std::map<const Gui::Document*, DocumentItem*>::iterator it;
00653                 it = DocumentMap.find(pDoc);
00654                 if (it != DocumentMap.end()) {
00655                     it->second->clearSelection();
00656                 }
00657             }
00658             this->update();
00659         }   break;
00660     case SelectionChanges::SetPreselect:
00661         {
00662             Gui::Document* pDoc = Application::Instance->getDocument(msg.pDocName);
00663             std::map<const Gui::Document*, DocumentItem*>::iterator it;
00664             it = DocumentMap.find(pDoc);
00665             if (it!= DocumentMap.end())
00666                 it->second->setObjectHighlighted(msg.pObjectName,true);
00667         }   break;
00668     case SelectionChanges::RmvPreselect:
00669         {
00670             Gui::Document* pDoc = Application::Instance->getDocument(msg.pDocName);
00671             std::map<const Gui::Document*, DocumentItem*>::iterator it;
00672             it = DocumentMap.find(pDoc);
00673             if (it!= DocumentMap.end())
00674                 it->second->setObjectHighlighted(msg.pObjectName,false);
00675         }   break;
00676     default:
00677         break;
00678     }
00679 }
00680 
00681 void TreeWidget::setItemsSelected (const QList<QTreeWidgetItem *> items, bool select)
00682 {
00683     if (items.isEmpty())
00684         return;
00685     QItemSelection range;
00686     for (QList<QTreeWidgetItem*>::const_iterator it = items.begin(); it != items.end(); ++it)
00687         range.select(this->indexFromItem(*it),this->indexFromItem(*it));
00688     selectionModel()->select(range, select ? 
00689         QItemSelectionModel::Select :
00690         QItemSelectionModel::Deselect);
00691 }
00692 
00693 // ----------------------------------------------------------------------------
00694 
00695 /* TRANSLATOR Gui::TreeDockWidget */
00696 TreeDockWidget::TreeDockWidget(Gui::Document* pcDocument,QWidget *parent)
00697   : DockWindow(pcDocument,parent)
00698 {
00699     setWindowTitle(tr("Tree view"));
00700     this->treeWidget = new TreeWidget(this);
00701     this->treeWidget->setRootIsDecorated(false);
00702 
00703     QGridLayout* pLayout = new QGridLayout(this); 
00704     pLayout->setSpacing(0);
00705     pLayout->setMargin (0);
00706     pLayout->addWidget(this->treeWidget, 0, 0 );
00707 }
00708 
00709 TreeDockWidget::~TreeDockWidget()
00710 {
00711 }
00712 
00713 // ----------------------------------------------------------------------------
00714 
00715 DocumentItem::DocumentItem(const Gui::Document* doc, QTreeWidgetItem * parent)
00716     : QTreeWidgetItem(parent, TreeWidget::DocumentType), pDocument(doc)
00717 {
00718     // Setup connections
00719     doc->signalNewObject.connect(boost::bind(&DocumentItem::slotNewObject, this, _1));
00720     doc->signalDeletedObject.connect(boost::bind(&DocumentItem::slotDeleteObject, this, _1));
00721     doc->signalChangedObject.connect(boost::bind(&DocumentItem::slotChangeObject, this, _1));
00722     doc->signalRenamedObject.connect(boost::bind(&DocumentItem::slotRenameObject, this, _1));
00723     doc->signalActivatedObject.connect(boost::bind(&DocumentItem::slotActiveObject, this, _1));
00724     doc->signalInEdit.connect(boost::bind(&DocumentItem::slotInEdit, this, _1));
00725     doc->signalResetEdit.connect(boost::bind(&DocumentItem::slotResetEdit, this, _1));
00726 
00727     setFlags(Qt::ItemIsEnabled/*|Qt::ItemIsEditable*/);
00728 }
00729 
00730 DocumentItem::~DocumentItem()
00731 {
00732 }
00733 
00734 void DocumentItem::slotInEdit(const Gui::ViewProviderDocumentObject& v)
00735 {
00736     std::string name (v.getObject()->getNameInDocument());
00737     std::map<std::string, DocumentObjectItem*>::iterator it = ObjectMap.find(name);
00738     if (it != ObjectMap.end()) 
00739         it->second->setBackgroundColor(0,Qt::yellow);
00740 }
00741 
00742 void DocumentItem::slotResetEdit(const Gui::ViewProviderDocumentObject& v)
00743 {
00744     std::string name (v.getObject()->getNameInDocument());
00745     std::map<std::string, DocumentObjectItem*>::iterator it = ObjectMap.find(name);
00746     if (it != ObjectMap.end()) {
00747         it->second->setData(0, Qt::BackgroundColorRole,QVariant());
00748     }
00749 }
00750 
00751 void DocumentItem::slotNewObject(const Gui::ViewProviderDocumentObject& obj)
00752 {
00753     std::string displayName = obj.getObject()->Label.getValue();
00754     std::string objectName = obj.getObject()->getNameInDocument();
00755     std::map<std::string, DocumentObjectItem*>::iterator it = ObjectMap.find(objectName);
00756     if (it == ObjectMap.end()) {
00757         // cast to non-const object
00758         DocumentObjectItem* item = new DocumentObjectItem(
00759             const_cast<Gui::ViewProviderDocumentObject*>(&obj), this);
00760         item->setIcon(0, obj.getIcon());
00761         item->setText(0, QString::fromUtf8(displayName.c_str()));
00762         ObjectMap[objectName] = item;
00763     } else {
00764         Base::Console().Warning("DocumentItem::slotNewObject: Cannot add view provider twice.\n");
00765     }
00766 }
00767 
00768 void DocumentItem::slotDeleteObject(const Gui::ViewProviderDocumentObject& obj)
00769 {
00770     std::string objectName = obj.getObject()->getNameInDocument();
00771     std::map<std::string, DocumentObjectItem*>::iterator it = ObjectMap.find(objectName);
00772     if (it != ObjectMap.end()) {
00773         QTreeWidgetItem* parent = it->second->parent();
00774         if (it->second->childCount() > 0) {
00775             QList<QTreeWidgetItem*> children = it->second->takeChildren();
00776             parent->addChildren(children);
00777         }
00778 
00779         parent->takeChild(parent->indexOfChild(it->second));
00780         delete it->second;
00781         ObjectMap.erase(it);
00782     }
00783 }
00784 
00785 void DocumentItem::slotChangeObject(const Gui::ViewProviderDocumentObject& view)
00786 {
00787     // As we immediately add a newly created object to the tree we check here which
00788     // item (this or a DocumentObjectItem) is the parent of the associated item of 'view'
00789     App::DocumentObject* obj = view.getObject();
00790     std::string objectName = obj->getNameInDocument();
00791     std::map<std::string, DocumentObjectItem*>::iterator it = ObjectMap.find(objectName);
00792     if (it != ObjectMap.end()) {
00793          // use new grouping style
00794 #        if 1
00795             std::set<QTreeWidgetItem*> children;
00796             std::vector<App::DocumentObject*> group = view.claimChildren();
00797             for (std::vector<App::DocumentObject*>::iterator jt = group.begin(); jt != group.end(); ++jt) {
00798                 if(*jt){
00799                     const char* internalName = (*jt)->getNameInDocument();
00800                     if (internalName) {
00801                         std::map<std::string, DocumentObjectItem*>::iterator kt = ObjectMap.find(internalName);
00802                         if (kt != ObjectMap.end()) {
00803                             children.insert(kt->second);
00804                             QTreeWidgetItem* parent = kt->second->parent();
00805                             if (parent && parent != it->second) {
00806                                 int index = parent->indexOfChild(kt->second);
00807                                 parent->takeChild(index);
00808                                 it->second->addChild(kt->second);
00809                             }
00810                         }
00811                         else {
00812                             Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Cannot reparent unknown object.\n");
00813                         }
00814                     }
00815                     else {
00816                         Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Group references unknown object.\n");
00817                     }
00818                 }
00819             }
00820             // move all children which are not part of the group anymore to this item
00821             int count = it->second->childCount();
00822             for (int i=0; i < count; i++) {
00823                 QTreeWidgetItem* child = it->second->child(i);
00824                 if (children.find(child) == children.end()) {
00825                     it->second->takeChild(i);
00826                     this->addChild(child);
00827                 }
00828             }
00829             //this->treeWidget()->expandItem(it->second);
00830          // old grouping style here
00831 #        else 
00832 
00833             // is the object a group?
00834             if (obj->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId())) {
00835                 std::set<QTreeWidgetItem*> children;
00836                 std::vector<App::DocumentObject*> group = static_cast<App::DocumentObjectGroup*>(obj)->Group.getValues();
00837                 for (std::vector<App::DocumentObject*>::iterator jt = group.begin(); jt != group.end(); ++jt) {
00838                     const char* internalName = (*jt)->getNameInDocument();
00839                     if (internalName) {
00840                         std::map<std::string, DocumentObjectItem*>::iterator kt = ObjectMap.find(internalName);
00841                         if (kt != ObjectMap.end()) {
00842                             children.insert(kt->second);
00843                             QTreeWidgetItem* parent = kt->second->parent();
00844                             if (parent && parent != it->second) {
00845                                 int index = parent->indexOfChild(kt->second);
00846                                 parent->takeChild(index);
00847                                 it->second->addChild(kt->second);
00848                             }
00849                         }
00850                         else {
00851                             Base::Console().Warning("DocumentItem::slotChangedObject: Cannot reparent unknown object.\n");
00852                         }
00853                     }
00854                     else {
00855                         Base::Console().Warning("DocumentItem::slotChangedObject: Group references unknown object.\n");
00856                     }
00857                 }
00858 
00859                 // move all children which are not part of the group anymore to this item
00860                 int count = it->second->childCount();
00861                 for (int i=0; i < count; i++) {
00862                     QTreeWidgetItem* child = it->second->child(i);
00863                     if (children.find(child) == children.end()) {
00864                         it->second->takeChild(i);
00865                         this->addChild(child);
00866                     }
00867                 }
00868                 this->treeWidget()->expandItem(it->second);
00869             }
00870         // end of grouping style switch
00871 #       endif 
00872         // set the text label
00873         std::string displayName = obj->Label.getValue();
00874         it->second->setText(0, QString::fromUtf8(displayName.c_str()));
00875     } else {
00876         Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Cannot change unknown object.\n");
00877     }
00878 }
00879 
00880 void DocumentItem::slotRenameObject(const Gui::ViewProviderDocumentObject& obj)
00881 {
00882     for (std::map<std::string,DocumentObjectItem*>::iterator it = ObjectMap.begin(); it != ObjectMap.end(); ++it) {
00883         if (it->second->object() == &obj) {
00884             DocumentObjectItem* item = it->second;
00885             ObjectMap.erase(it);
00886             std::string objectName = obj.getObject()->getNameInDocument();
00887             ObjectMap[objectName] = item;
00888             return;
00889         }
00890     }
00891 
00892     // no such object found
00893     Base::Console().Warning("DocumentItem::slotRenamedObject: Cannot rename unknown object.\n");
00894 }
00895 
00896 void DocumentItem::slotActiveObject(const Gui::ViewProviderDocumentObject& obj)
00897 {
00898     std::string objectName = obj.getObject()->getNameInDocument();
00899     std::map<std::string, DocumentObjectItem*>::iterator jt = ObjectMap.find(objectName);
00900     if (jt == ObjectMap.end())
00901         return; // signal is emitted before the item gets created
00902     for (std::map<std::string, DocumentObjectItem*>::iterator it = ObjectMap.begin();
00903          it != ObjectMap.end(); ++it)
00904     {
00905         QFont f = it->second->font(0);
00906         f.setBold(it == jt);
00907         it->second->setFont(0,f);
00908     }
00909 }
00910 
00911 const Gui::Document* DocumentItem::document() const
00912 {
00913     return this->pDocument;
00914 }
00915 
00916 void DocumentItem::testStatus(void)
00917 {
00918     for (std::map<std::string,DocumentObjectItem*>::iterator pos = ObjectMap.begin();pos!=ObjectMap.end();++pos) {
00919         pos->second->testStatus();
00920     }
00921 }
00922 
00923 void DocumentItem::setData (int column, int role, const QVariant & value)
00924 {
00925     if (role == Qt::EditRole) {
00926         QString label = value.toString();
00927         pDocument->getDocument()->Label.setValue((const char*)label.toUtf8());
00928     }
00929 
00930     QTreeWidgetItem::setData(column, role, value);
00931 }
00932 
00933 void DocumentItem::setObjectHighlighted(const char* name, bool select)
00934 {
00935     std::map<std::string,DocumentObjectItem*>::iterator pos;
00936     pos = ObjectMap.find(name);
00937     if (pos != ObjectMap.end()) {
00938         //pos->second->setData(0, Qt::TextColorRole, QVariant(Qt::red));
00939         //treeWidget()->setItemSelected(pos->second, select);
00940     }
00941 }
00942 
00943 void DocumentItem::setObjectSelected(const char* name, bool select)
00944 {
00945     std::map<std::string,DocumentObjectItem*>::iterator pos;
00946     pos = ObjectMap.find(name);
00947     if (pos != ObjectMap.end()) {
00948         treeWidget()->setItemSelected(pos->second, select);
00949     }
00950 }
00951 
00952 void DocumentItem::clearSelection(void)
00953 {
00954     for (std::map<std::string,DocumentObjectItem*>::iterator pos = ObjectMap.begin();pos!=ObjectMap.end();++pos) {
00955         treeWidget()->setItemSelected(pos->second, false);
00956     }
00957 }
00958 
00959 void DocumentItem::updateSelection(void)
00960 {
00961     std::vector<App::DocumentObject*> sel;
00962     for (std::map<std::string,DocumentObjectItem*>::iterator pos = ObjectMap.begin();pos!=ObjectMap.end();++pos) {
00963         if (treeWidget()->isItemSelected(pos->second)) {
00964             sel.push_back(pos->second->object()->getObject());
00965         }
00966     }
00967 
00968     Gui::Selection().setSelection(pDocument->getDocument()->getName(), sel);
00969 }
00970 
00971 namespace Gui {
00972 struct ObjectItem_Less : public std::binary_function<DocumentObjectItem*,
00973                                                      DocumentObjectItem*, bool>
00974 {
00975     bool operator()(DocumentObjectItem* x, DocumentObjectItem* y) const
00976     {
00977         return x->object()->getObject() < y->object()->getObject();
00978     }
00979 };
00980 
00981 struct ObjectItem_Equal : public std::binary_function<DocumentObjectItem*,
00982                                                       App::DocumentObject*, bool>
00983 {
00984     bool operator()(DocumentObjectItem* x, App::DocumentObject* y) const
00985     {
00986         return x->object()->getObject() == y;
00987     }
00988 };
00989 }
00990 
00991 void DocumentItem::selectItems(void)
00992 {
00993     // get an array of all tree items of the document and sort it in ascending order
00994     // with regard to their document object
00995     std::vector<DocumentObjectItem*> items;
00996     for (std::map<std::string,DocumentObjectItem*>::iterator it = ObjectMap.begin(); it != ObjectMap.end(); ++it) {
00997         items.push_back(it->second);
00998     }
00999     std::sort(items.begin(), items.end(), ObjectItem_Less());
01000 
01001     // get and sort all selected document objects of the given document
01002     std::vector<App::DocumentObject*> objs;
01003     std::vector<SelectionSingleton::SelObj> obj = Selection().getSelection(pDocument->getDocument()->getName());
01004     for (std::vector<SelectionSingleton::SelObj>::iterator jt = obj.begin(); jt != obj.end(); ++jt) {
01005         objs.push_back(jt->pObject);
01006     }
01007     std::sort(objs.begin(), objs.end());
01008 
01009     // The document objects in 'objs' is a subset of the document objects stored
01010     // in 'items'. Since both arrays are sorted we get the wanted tree items in
01011     // linear time.
01012     std::vector<DocumentObjectItem*> common;
01013     std::vector<DocumentObjectItem*>::iterator item_it = items.begin();
01014     for (std::vector<App::DocumentObject*>::iterator it = objs.begin(); it != objs.end(); ++it) {
01015         item_it = std::find_if(item_it, items.end(), std::bind2nd(ObjectItem_Equal(), *it));
01016         if (item_it == items.end())
01017             break; // should never ever happen
01018         common.push_back(*item_it);
01019     }
01020 
01021     // get all unselected items of the given document
01022     std::sort(common.begin(), common.end());
01023     std::sort(items.begin(), items.end());
01024     std::vector<DocumentObjectItem*> diff;
01025     std::back_insert_iterator<std::vector<DocumentObjectItem*> > biit(diff);
01026     std::set_difference(items.begin(), items.end(), common.begin(), common.end(), biit);
01027 
01028     // select the appropriate items
01029     QList<QTreeWidgetItem *> selitems;
01030     for (std::vector<DocumentObjectItem*>::iterator it = common.begin(); it != common.end(); ++it)
01031         selitems.append(*it);
01032     static_cast<TreeWidget*>(treeWidget())->setItemsSelected(selitems, true);
01033     // deselect the appropriate items
01034     QList<QTreeWidgetItem *> deselitems;
01035     for (std::vector<DocumentObjectItem*>::iterator it = diff.begin(); it != diff.end(); ++it)
01036         deselitems.append(*it);
01037     static_cast<TreeWidget*>(treeWidget())->setItemsSelected(deselitems, false);
01038 }
01039 
01040 // ----------------------------------------------------------------------------
01041 
01042 DocumentObjectItem::DocumentObjectItem(Gui::ViewProviderDocumentObject* pcViewProvider,
01043                                        QTreeWidgetItem* parent)
01044     : QTreeWidgetItem(parent, TreeWidget::ObjectType), previousStatus(-1), viewObject(pcViewProvider)
01045 {
01046     setFlags(flags()|Qt::ItemIsEditable);
01047     // Setup connections
01048     connectIcon = pcViewProvider->signalChangeIcon.connect(boost::bind(&DocumentObjectItem::slotChangeIcon, this));
01049     connectTool = pcViewProvider->signalChangeToolTip.connect(boost::bind(&DocumentObjectItem::slotChangeToolTip, this, _1));
01050     connectStat = pcViewProvider->signalChangeStatusTip.connect(boost::bind(&DocumentObjectItem::slotChangeStatusTip, this, _1));
01051 }
01052 
01053 DocumentObjectItem::~DocumentObjectItem()
01054 {
01055     connectIcon.disconnect();
01056     connectTool.disconnect();
01057     connectStat.disconnect();
01058 }
01059 
01060 Gui::ViewProviderDocumentObject* DocumentObjectItem::object() const
01061 {
01062     return viewObject;
01063 }
01064 
01065 void DocumentObjectItem::testStatus()
01066 {
01067     App::DocumentObject* pObject = viewObject->getObject();
01068 
01069     // if status has changed then continue
01070     int currentStatus = 
01071         ((pObject->isError()          ? 1 : 0) << 2) |
01072         ((pObject->mustExecute() == 1 ? 1 : 0) << 1) |
01073         (viewObject->isShow()         ? 1 : 0);
01074     if (previousStatus == currentStatus)
01075         return;
01076     previousStatus = currentStatus;
01077 
01078     QPixmap px;
01079     if (currentStatus & 4) {
01080         // object is in error state
01081         static const char * const feature_error_xpm[]={
01082             "9 9 3 1",
01083             ". c None",
01084             "# c #ff0000",
01085             "a c #ffffff",
01086             "...###...",
01087             ".##aaa##.",
01088             ".##aaa##.",
01089             "###aaa###",
01090             "###aaa###",
01091             "#########",
01092             ".##aaa##.",
01093             ".##aaa##.",
01094             "...###..."};
01095         px = QPixmap(feature_error_xpm);
01096     }
01097     else if (currentStatus & 2) {
01098         // object must be recomputed
01099         static const char * const feature_recompute_xpm[]={
01100             "9 9 3 1",
01101             ". c None",
01102             "# c #0000ff",
01103             "a c #ffffff",
01104             "...###...",
01105             ".######aa",
01106             ".#####aa.",
01107             "#####aa##",
01108             "#aa#aa###",
01109             "#aaaa####",
01110             ".#aa####.",
01111             ".#######.",
01112             "...###..."};
01113         px = QPixmap(feature_recompute_xpm);
01114     }
01115 
01116     QIcon::Mode mode = QIcon::Normal;
01117     if (currentStatus & 1) { // visible
01118         // Note: By default the foreground, i.e. text color is invalid
01119         // to make use of the default color of the tree widget's palette.
01120         // If we temporarily set this color to dark and reset to an invalid
01121         // color again we cannot do it with setTextColor() or setForeground(),
01122         // respectively, because for any reason the color would always switch
01123         // to black which will lead to unreadable text if the system background
01124         // hss already a dark color.
01125         // However, it works if we set the appropriate role to an empty QVariant().
01126 #if QT_VERSION >= 0x040200
01127         this->setData(0, Qt::ForegroundRole,QVariant());
01128 #else
01129         this->setData(0, Qt::TextColorRole,QVariant());
01130 #endif
01131     }
01132     else { // invisible
01133         QStyleOptionViewItem opt;
01134         opt.initFrom(this->treeWidget());
01135 #if QT_VERSION >= 0x040200
01136         this->setForeground(0, opt.palette.color(QPalette::Disabled,QPalette::Dark));
01137 #else
01138         this->setTextColor(0, opt.palette.color(QPalette::Disabled,QPalette::Dark));
01139 #endif
01140         mode = QIcon::Disabled;
01141     }
01142 
01143     // get the original icon set
01144     QIcon icon_org = viewObject->getIcon();
01145     QIcon icon_mod;
01146     int w = QApplication::style()->pixelMetric(QStyle::PM_ListViewIconSize);
01147 
01148     // if needed show small pixmap inside
01149     if (!px.isNull()) {
01150         icon_mod.addPixmap(BitmapFactory().merge(icon_org.pixmap(w, w, mode, QIcon::Off),
01151             px,BitmapFactoryInst::TopRight), QIcon::Normal, QIcon::Off);
01152         icon_mod.addPixmap(BitmapFactory().merge(icon_org.pixmap(w, w, mode, QIcon::On ),
01153             px,BitmapFactoryInst::TopRight), QIcon::Normal, QIcon::Off);
01154     }
01155     else {
01156         icon_mod.addPixmap(icon_org.pixmap(w, w, mode, QIcon::Off), QIcon::Normal, QIcon::Off);
01157         icon_mod.addPixmap(icon_org.pixmap(w, w, mode, QIcon::On ), QIcon::Normal, QIcon::On );
01158     }
01159 
01160     this->setIcon(0, icon_mod);
01161 }
01162 
01163 void DocumentObjectItem::displayStatusInfo()
01164 {
01165     App::DocumentObject* Obj = viewObject->getObject();
01166 
01167     QString info = QString::fromAscii(Obj->getStatusString());
01168     if ( Obj->mustExecute() == 1 )
01169         info += QString::fromAscii(" (but must be executed)");
01170     getMainWindow()->statusBar()->showMessage( info );
01171    
01172 }
01173 
01174 void DocumentObjectItem::setData (int column, int role, const QVariant & value)
01175 {
01176     QTreeWidgetItem::setData(column, role, value);
01177     if (role == Qt::EditRole) {
01178         QString label = value.toString();
01179         viewObject->getObject()->Label.setValue((const char*)label.toUtf8());
01180     }
01181 }
01182 
01183 void DocumentObjectItem::slotChangeIcon()
01184 {
01185     previousStatus = -1;
01186     testStatus();
01187 }
01188 
01189 void DocumentObjectItem::slotChangeToolTip(const QString& tip)
01190 {
01191     this->setToolTip(0, tip);
01192 }
01193 
01194 void DocumentObjectItem::slotChangeStatusTip(const QString& tip)
01195 {
01196     this->setStatusTip(0, tip);
01197 }
01198 
01199 
01200 
01201 #include "moc_Tree.cpp"
01202 

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