// Copyright (C) 2015-2016 CEA/DEN, EDF R&D, OPEN CASCADE // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File : GEOMGUI_TextTreeWdg.cxx // Author : Alexander KOVALEV (akl) #include "GEOMGUI_TextTreeWdg.h" #include "GEOMGUI_DimensionProperty.h" #include "GEOMGUI_AnnotationAttrs.h" #include "GeometryGUI.h" #include "GeometryGUI_Operations.h" #include #include // GUI includes #include #include #include #include #include #include #include // Qt includes #include #include #include #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // Common style interface for managing dimension and annotation properties // ---------------------------------------------------------------------------- namespace { //! Access interface implementation for shape dimension attribute/property. class DimensionsProperty : public GEOMGUI_TextTreeWdg::VisualProperty { public: DimensionsProperty( SalomeApp_Study* theStudy, const std::string& theEntry ) : myStudy( theStudy ), myEntry( theEntry ) { myAttr.LoadFromAttribute( theStudy, theEntry ); } virtual int GetNumber() Standard_OVERRIDE { return myAttr.GetNumber(); } virtual QString GetName( const int theIndex ) Standard_OVERRIDE { return myAttr.GetName( theIndex ); } virtual bool GetIsVisible( const int theIndex ) Standard_OVERRIDE { return myAttr.IsVisible( theIndex ); } virtual void SetIsVisible( const int theIndex, const bool theIsVisible ) Standard_OVERRIDE { myAttr.SetVisible( theIndex, theIsVisible ); } virtual void Save() Standard_OVERRIDE { myAttr.SaveToAttribute( myStudy, myEntry ); } GEOMGUI_DimensionProperty& Attr() { return myAttr; } private: GEOMGUI_DimensionProperty myAttr; SalomeApp_Study* myStudy; std::string myEntry; }; //! Access interface implementation for shape annotation attribute. class AnnotationsProperty : public GEOMGUI_TextTreeWdg::VisualProperty { public: AnnotationsProperty( SalomeApp_Study* theStudy, const std::string& theEntry ) { _PTR(SObject) aSObj = theStudy->studyDS()->FindObjectID( theEntry ); myAttr = GEOMGUI_AnnotationAttrs::FindAttributes( aSObj ); } virtual int GetNumber() Standard_OVERRIDE { return !myAttr.IsNull() ? myAttr->GetNbAnnotation() : 0; } virtual QString GetName( const int theIndex ) Standard_OVERRIDE { return !myAttr.IsNull() ? myAttr->GetName( theIndex ) : QString(); } virtual bool GetIsVisible( const int theIndex ) Standard_OVERRIDE { return !myAttr.IsNull() ? myAttr->GetIsVisible( theIndex ) : false; } virtual void SetIsVisible( const int theIndex, const bool theIsVisible ) Standard_OVERRIDE { if ( !myAttr.IsNull() ) { myAttr->SetIsVisible( theIndex, theIsVisible ); } } virtual void Save() Standard_OVERRIDE { /* every change is automatically saved */ } Handle(GEOMGUI_AnnotationAttrs) Attr() { return myAttr; } private: Handle(GEOMGUI_AnnotationAttrs) myAttr; }; } // ---------------------------------------------------------------------------- // Text tree widget implementation // ---------------------------------------------------------------------------- GEOMGUI_TextTreeWdg::GEOMGUI_TextTreeWdg( SalomeApp_Application* app ) : myDisplayer(NULL) { myStudy = dynamic_cast( app->activeStudy() ); myDisplayer = GEOM_Displayer( myStudy ); SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); myVisibleIcon = QIcon( resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_VISIBLE" ) ) ); myInvisibleIcon = QIcon( resMgr->loadPixmap( "SUIT", tr( "ICON_DATAOBJ_INVISIBLE" ) ) ); setWindowTitle( tr( "TEXT_TREE_VIEW_TITLE" ) ); setObjectName( "geomTextTreeWdg" ); setRootIsDecorated( true ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setAllColumnsShowFocus( true ); setUniformRowHeights( true ); QStringList columnNames; columnNames << tr("TEXT_TREE_VIEW_NAME") << ""; QTreeWidgetItem * headerItem = new QTreeWidgetItem( columnNames ); headerItem->setIcon( 1, myVisibleIcon ); setHeaderItem ( headerItem ); header()->moveSection( 1, 0 ); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) header()->setResizeMode( 1, QHeaderView::ResizeToContents ); #else header()->setSectionResizeMode( 1, QHeaderView::ResizeToContents ); #endif QStringList rootNames; rootNames << tr("GEOM_DIMENSIONS") << ""; myDimensionsItem = new QTreeWidgetItem( this, rootNames ); myDimensionsItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); addTopLevelItem( myDimensionsItem ); rootNames.clear(); rootNames << tr("GEOM_ANNOTATIONS") << ""; myAnnotationsItem = new QTreeWidgetItem( this, rootNames ); myAnnotationsItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); addTopLevelItem( myAnnotationsItem ); // get a free dockable window id myWindowID = 11; while( app->dockWindow( myWindowID )) ++myWindowID; ++myWindowID; createActions(); setContextMenuPolicy( Qt::CustomContextMenu ); connect( this, SIGNAL( customContextMenuRequested(const QPoint&) ), this, SLOT( showContextMenu(const QPoint&) ) ); connect( myStudy, SIGNAL( objVisibilityChanged( QString, Qtx::VisibilityState ) ), this, SLOT( updateVisibilityColumn( QString, Qtx::VisibilityState ) ) ); connect( app->objectBrowser(), SIGNAL( updated() ), this, SLOT( updateTree() ) ); GeometryGUI* aGeomGUI = dynamic_cast( app->module( "Geometry" ) ); connect( aGeomGUI, SIGNAL( DimensionsUpdated( const QString& ) ), this, SLOT( updateBranch( const QString& ) ) ); connect( this, SIGNAL( itemClicked( QTreeWidgetItem*, int) ), this, SLOT( onItemClicked( QTreeWidgetItem*, int ) ) ); } GEOMGUI_TextTreeWdg::~GEOMGUI_TextTreeWdg() { //std::cout<<"~GEOMGUI_TextTreeWdg"<setIcon( myVisibleIcon ); myActions.insert( GEOMOp::OpShow, a ); QAction* b = new QAction( tr( "MEN_ERASE" ), this ); b->setIcon( myInvisibleIcon ); myActions.insert( GEOMOp::OpHide, b ); } //================================================================================= // function : updateTree // purpose : //================================================================================= void GEOMGUI_TextTreeWdg::updateTree() { myStudy = dynamic_cast( SUIT_Session::session()->activeApplication()->activeStudy() ); _PTR(Study) aDSStudy = myStudy->studyDS(); if ( aDSStudy ) { _PTR(SComponent) SC ( aDSStudy->FindComponent( "GEOM" ) ); if ( SC ) { _PTR(ChildIterator) anIter ( aDSStudy->NewChildIterator( SC ) ); anIter->InitEx( true ); QList aDimensionObjEntries = getObjects( DimensionShape ).keys(); QList anAnnotationObjEntries = getObjects( AnnotationShape ).keys(); while( anIter->More() ) { _PTR(SObject) valSO ( anIter->Value() ); _PTR(SObject) refSO; if ( !valSO->ReferencedObject( refSO ) ) { // update tree of object's dimensions QString anEntry = valSO->GetID().c_str(); updateBranch( anEntry ); aDimensionObjEntries.removeAll( anEntry ); anAnnotationObjEntries.removeAll( anEntry ); } anIter->Next(); } foreach ( QString entry, aDimensionObjEntries ) { removeBranch( DimensionShape, entry, true ); } foreach ( QString entry, anAnnotationObjEntries ) { removeBranch( AnnotationShape, entry, true ); } } } } //================================================================================= // function : updateBranch // purpose : //================================================================================= void GEOMGUI_TextTreeWdg::updateBranch( const QString& theEntry ) { // dimension property branch fillBranch( DimensionShape, theEntry ); // annotation property branch fillBranch( AnnotationShape, theEntry ); } //================================================================================= // function : fillBranch // purpose : //================================================================================= void GEOMGUI_TextTreeWdg::fillBranch( const BranchType& theBranchType, const QString& theEntry ) { myStudy = dynamic_cast( SUIT_Session::session()->activeApplication()->activeStudy() ); if ( myStudy && !theEntry.isEmpty() ) { QSharedPointer aProp = getVisualProperty( theBranchType, myStudy, theEntry.toStdString() ); const std::string anEntry = theEntry.toStdString(); if ( !aProp ) { return; } _PTR(Study) aStudyDS = myStudy->studyDS(); if ( aStudyDS ) { _PTR(SObject) obj( aStudyDS->FindObjectID( theEntry.toStdString() ) ); const QString aName = obj->GetName().c_str(); const int nbProps = aProp->GetNumber(); QTreeWidgetItem* objectItem = itemFromEntry( theBranchType, theEntry ); if ( objectItem ) { removeBranch( theBranchType, theEntry, nbProps > 0 ? false : true ); } QStringList itemName; if ( nbProps > 0 ) { itemName << aName << ""; if ( !objectItem ) { QTreeWidgetItem* aPropRootItem = getPropertyRootItem( theBranchType ); objectItem = new QTreeWidgetItem( aPropRootItem, itemName ); objectItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); objectItem->setData( 1, Qt::UserRole, theEntry ); aPropRootItem->addChild( objectItem ); getObjects( theBranchType ).insert( theEntry, objectItem ); if ( aPropRootItem->childCount() == 1 ) aPropRootItem->setExpanded( true ); } for ( int anIt = 0; anIt < nbProps; ++anIt ) { const QString aPropName = aProp->GetName( anIt ); const bool isVisible = aProp->GetIsVisible( anIt ); QTreeWidgetItem* anItem = new QTreeWidgetItem; anItem->setText( 0, aPropName ); anItem->setIcon( 1, isVisible ? myVisibleIcon : myInvisibleIcon ); anItem->setData( 0, Qt::UserRole, anIt ); anItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); objectItem->addChild( anItem ); } } } } } //================================================================================= // function : getVisualProperty // purpose : //================================================================================= QSharedPointer GEOMGUI_TextTreeWdg::getVisualProperty( const BranchType& theBranchType, SalomeApp_Study* theStudy, const std::string& theEntry ) { switch ( theBranchType ) { case DimensionShape : return QSharedPointer( new DimensionsProperty( theStudy, theEntry ) ); case AnnotationShape : return QSharedPointer( new AnnotationsProperty( theStudy, theEntry ) ); default: break; } return QSharedPointer(); } //================================================================================= // function : removeBranch // purpose : //================================================================================= void GEOMGUI_TextTreeWdg::removeBranch( const BranchType& theBranchType, const QString& theEntry, bool force ) { QTreeWidgetItem* objectItem = itemFromEntry( theBranchType, theEntry ); if ( !objectItem ) return; qDeleteAll( objectItem->takeChildren() ); if ( force ) { QTreeWidgetItem* aPropRootItem = getPropertyRootItem( theBranchType ); aPropRootItem->removeChild( objectItem ); getObjects( theBranchType ).remove( theEntry ); } } //================================================================================= // function : onItemClicked() // purpose : called when tree item was clicked //================================================================================= void GEOMGUI_TextTreeWdg::onItemClicked( QTreeWidgetItem* theItem, int theColumn ) { if( theColumn != 1 || theItem->icon( 1 ).isNull() || theItem->isDisabled() ) return; std::string anEntry = entryFromItem( theItem->parent() ).toStdString(); BranchType aBranchType = branchTypeFromItem( theItem ); int aDimIndex = idFromItem( theItem ); QSharedPointer aProp = getVisualProperty( aBranchType, myStudy, anEntry ); if ( aProp->GetIsVisible( aDimIndex ) ) { aProp->SetIsVisible( aDimIndex, false ); theItem->setIcon( 1, myInvisibleIcon ); } else { aProp->SetIsVisible( aDimIndex, true ); theItem->setIcon( 1, myVisibleIcon ); } aProp->Save(); redisplay( anEntry.c_str() ); } //================================================================================= // function : idFromItem // purpose : //================================================================================= int GEOMGUI_TextTreeWdg::idFromItem( QTreeWidgetItem* theItem ) { if ( !theItem ) return -1; bool isIdOK = false; const int anId = theItem->data( 0, Qt::UserRole ).toInt( &isIdOK ); return isIdOK ? anId : -1; } //================================================================================= // function : entryFromItem // purpose : //================================================================================= QString GEOMGUI_TextTreeWdg::entryFromItem( QTreeWidgetItem* theShapeItem ) { if ( !theShapeItem ) return ""; return theShapeItem->data( 1, Qt::UserRole ).toString(); } //================================================================================= // function : itemFromEntry // purpose : //================================================================================= QTreeWidgetItem* GEOMGUI_TextTreeWdg::itemFromEntry( const BranchType& theBranchType, QString theEntry ) { if ( theEntry.isEmpty() ) return 0; return getObjects(theBranchType).value( theEntry, 0 ); } //================================================================================= // function : updateVisibilityColumn // purpose : Update visible state of icons of entry items. //================================================================================= void GEOMGUI_TextTreeWdg::updateVisibilityColumn( QString theEntry, Qtx::VisibilityState theState ) { // dimension property branch updateVisibilityColumn( DimensionShape, theEntry, theState ); // annotation property branch updateVisibilityColumn( AnnotationShape, theEntry, theState ); } //================================================================================= // function : updateVisibilityColumn // purpose : Update icons of dimension items. //================================================================================= void GEOMGUI_TextTreeWdg::updateVisibilityColumn( const BranchType& theBranchType, QString theEntry, Qtx::VisibilityState theState ) { QTreeWidgetItem* anItem = itemFromEntry( theBranchType, theEntry ); if ( !anItem ) return; anItem->setDisabled( theState != Qtx::ShownState ); QTreeWidgetItem* aChildItem; QSharedPointer aProp = getVisualProperty( theBranchType, myStudy, theEntry.toStdString() ); for ( int i=0; i < anItem->childCount(); i++ ) { aChildItem = anItem->child( i ); if ( theState == Qtx::ShownState ) { if ( aProp->GetNumber() == 0 ) continue; aChildItem->setIcon( 1, aProp->GetIsVisible( idFromItem( aChildItem ) ) ? myVisibleIcon : myInvisibleIcon ); aChildItem->setDisabled( false ); } else { aChildItem->setIcon( 1, QIcon() ); aChildItem->setDisabled( true ); } } } //================================================================================= // function : showContextMenu // purpose : //================================================================================= void GEOMGUI_TextTreeWdg::showContextMenu( const QPoint& pos ) { if ( selectedItems().isEmpty() ) return; QMenu aMenu; aMenu.addAction( myActions[GEOMOp::OpShow] ); aMenu.addAction( myActions[GEOMOp::OpHide] ); if ( selectedItems().count() == 1 ) { QTreeWidgetItem* anItem = selectedItems().first(); QString anEntry = entryFromItem( anItem->parent() ); if ( !anEntry.isEmpty() ) { BranchType aBranchType = branchTypeFromItem( anItem ); QSharedPointer aProp = getVisualProperty( aBranchType, myStudy, anEntry.toStdString() ); if ( aProp->GetNumber() == 0 ) return; aMenu.clear(); if ( aProp->GetIsVisible( idFromItem( anItem ) ) ) aMenu.addAction( myActions[GEOMOp::OpHide] ); else aMenu.addAction( myActions[GEOMOp::OpShow] ); } } QAction* selPopupItem = aMenu.exec( viewport()->mapToGlobal(pos) ); if ( selPopupItem == myActions[GEOMOp::OpShow] || selPopupItem == myActions[GEOMOp::OpHide] ) { bool isVisible = selPopupItem == myActions[GEOMOp::OpShow]; foreach ( QTreeWidgetItem* anItem, selectedItems() ) { setVisibility( anItem, isVisible ); } } } //================================================================================= // function : setVisibility // purpose : set item visible //================================================================================= void GEOMGUI_TextTreeWdg::setVisibility( QTreeWidgetItem* theItem, bool theVisibility ) { BranchType aBranchType = branchTypeFromItem( theItem ); if ( theItem == myDimensionsItem || theItem == myAnnotationsItem ) { QTreeWidgetItem* anItem; foreach ( QString entry, getObjects( aBranchType ).keys() ) { anItem = itemFromEntry( aBranchType, entry ); if ( !anItem->isDisabled() ) setAllShapeItemsVisibility( aBranchType, entry, theVisibility ); } return; } else { if ( !theItem->isDisabled() && !theItem->parent()->isSelected() ) { QString anEntry = entryFromItem( theItem ); if ( !anEntry.isEmpty() ) { // it is a shape item setAllShapeItemsVisibility( aBranchType, anEntry, theVisibility ); } else { // it is a dimension item anEntry = entryFromItem( theItem->parent() ); setShapeItemVisibility( aBranchType, anEntry, theItem, theVisibility ); } } } } //================================================================================= // function : setAllShapeItemsVisibility // purpose : //================================================================================= void GEOMGUI_TextTreeWdg::setAllShapeItemsVisibility( const BranchType& theBranchType, const QString& theEntry, const bool theVisibility ) { QSharedPointer aProp = getVisualProperty( theBranchType, myStudy, theEntry.toStdString() ); QTreeWidgetItem* anItem = itemFromEntry( theBranchType, theEntry ); QTreeWidgetItem* aChildItem; for ( int i=0; i < anItem->childCount(); i++ ) { aChildItem = anItem->child( i ); setShapeItemVisibility( aProp, aChildItem, theVisibility ); } aProp->Save(); redisplay( theEntry ); } //================================================================================= // function : setShapeItemVisibility // purpose : //================================================================================= void GEOMGUI_TextTreeWdg::setShapeItemVisibility( const BranchType& theBranchType, const QString& theEntry, QTreeWidgetItem* theWidgetItem, const bool theVisibility ) { QSharedPointer aProp = getVisualProperty( theBranchType, myStudy, theEntry.toStdString() ); if ( setShapeItemVisibility( aProp, theWidgetItem, theVisibility ) ) { aProp->Save(); redisplay( theEntry ); } } //================================================================================= // function : setShapeItemVisibility // purpose : //================================================================================= bool GEOMGUI_TextTreeWdg::setShapeItemVisibility( QSharedPointer& theProps, QTreeWidgetItem* theWidgetItem, const bool theVisibility ) { int aDimIndex = idFromItem( theWidgetItem ); if ( theProps->GetNumber() == 0 || theProps->GetIsVisible( aDimIndex ) == theVisibility ) { return false; } theProps->SetIsVisible( aDimIndex, theVisibility ); theWidgetItem->setIcon( 1, theVisibility ? myVisibleIcon : myInvisibleIcon ); return true; } //================================================================================= // function : redisplay // purpose : //================================================================================= void GEOMGUI_TextTreeWdg::redisplay( QString theEntry ) { Handle(SALOME_InteractiveObject) io = new SALOME_InteractiveObject( theEntry.toLatin1().constData(), "GEOM", "TEMP_IO" ); myDisplayer.Redisplay( io ); } //================================================================================= // function : getPropertyRootItem // purpose : //================================================================================= QTreeWidgetItem* GEOMGUI_TextTreeWdg::getPropertyRootItem( const BranchType& theBranchType ) { return (theBranchType == DimensionShape) ? myDimensionsItem : myAnnotationsItem; } //================================================================================= // function : getObjects // purpose : //================================================================================= QHash& GEOMGUI_TextTreeWdg::getObjects( const BranchType& theBranchType ) { return (theBranchType == DimensionShape) ? myDimensionObjects : myAnnotationObjects; } //================================================================================= // function : branchTypeFromItem // purpose : //================================================================================= GEOMGUI_TextTreeWdg::BranchType GEOMGUI_TextTreeWdg::branchTypeFromItem( QTreeWidgetItem* theItem ) { BranchType aBranchType = DimensionShape; bool aBranchTypeFound = false; QTreeWidgetItem* anItem = theItem; while( !aBranchTypeFound && anItem ) { if ( anItem == myDimensionsItem || anItem == myAnnotationsItem) { aBranchTypeFound = true; aBranchType = (anItem == myDimensionsItem) ? DimensionShape : AnnotationShape; } else { anItem = anItem->parent(); } } return aBranchType; }