00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
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
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
00106 this->setMouseTracking(true);
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
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
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
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
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
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
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
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
00396 if (!targetitem)
00397 return;
00398
00399 if (this->isItemSelected(targetitem))
00400 return;
00401
00402
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;
00416
00417 if (targetitem->type() == TreeWidget::ObjectType) {
00418
00419 App::DocumentObject* grp = static_cast<DocumentObjectItem*>(targetitem)
00420 ->object()->getObject();
00421 if (!grp->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId()))
00422 return;
00423
00424
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
00430 App::DocumentObject* obj = static_cast<DocumentObjectItem*>(*it)
00431 ->object()->getObject();
00432 App::DocumentObjectGroup* par = App::DocumentObjectGroup
00433 ::getGroupOfObject(obj);
00434 if (par) {
00435
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
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
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
00461
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
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
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
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;
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
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
00594 if (this->isConnectionBlocked())
00595 return;
00596
00597
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
00636
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
00646 if (strcmp(msg.pDocName,"") == 0) {
00647 this->clearSelection ();
00648 }
00649 else {
00650
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
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
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);
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
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
00788
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
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
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
00830
00831 # else
00832
00833
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
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
00871 # endif
00872
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
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;
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
00939
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
00994
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
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
01010
01011
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;
01018 common.push_back(*item_it);
01019 }
01020
01021
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
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
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
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
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
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
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) {
01118
01119
01120
01121
01122
01123
01124
01125
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 {
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
01144 QIcon icon_org = viewObject->getIcon();
01145 QIcon icon_mod;
01146 int w = QApplication::style()->pixelMetric(QStyle::PM_ListViewIconSize);
01147
01148
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