// Created on: 2017-06-16 // Created by: Natalia ERMOLAEVA // Copyright (c) 2017 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const int DEFAULT_TEXT_VIEW_WIDTH = 800; const int DEFAULT_TEXT_VIEW_HEIGHT = 700; const int DEFAULT_TEXT_VIEW_POSITION_X = 430; const int DEFAULT_TEXT_VIEW_POSITION_Y = 30; const int DEFAULT_TEXT_VIEW_DELTA = 100; const int DEFAULT_SHAPE_VIEW_WIDTH = 900; const int DEFAULT_SHAPE_VIEW_HEIGHT = 450; const int DEFAULT_SHAPE_VIEW_POSITION_X = 60; const int DEFAULT_SHAPE_VIEW_POSITION_Y = 60; const int SHAPEVIEW_DEFAULT_TREE_VIEW_WIDTH = 600; const int SHAPEVIEW_DEFAULT_TREE_VIEW_HEIGHT = 500; const int SHAPEVIEW_DEFAULT_VIEW_WIDTH = 300; const int SHAPEVIEW_DEFAULT_VIEW_HEIGHT = 1000; // ======================================================================= // function : Constructor // purpose : // ======================================================================= ShapeView_Window::ShapeView_Window (QWidget* theParent) : QObject (theParent), myNextPosition (0) { myMainWindow = new QMainWindow (theParent); myTreeView = new ViewControl_TreeView (myMainWindow); ((ViewControl_TreeView*)myTreeView)->SetPredefinedSize (QSize (SHAPEVIEW_DEFAULT_TREE_VIEW_WIDTH, SHAPEVIEW_DEFAULT_TREE_VIEW_HEIGHT)); myTreeView->setContextMenuPolicy (Qt::CustomContextMenu); connect (myTreeView, SIGNAL (customContextMenuRequested (const QPoint&)), this, SLOT (onTreeViewContextMenuRequested (const QPoint&))); new TreeModel_ContextMenu (myTreeView); ShapeView_TreeModel* aModel = new ShapeView_TreeModel (myTreeView); for (int i = 5; i <= 6; i++) // hide shape parameters columns { TreeModel_HeaderSection anItem = aModel->GetHeaderItem (i); anItem.SetIsHidden (true); aModel->SetHeaderItem (i, anItem); } myTreeView->setModel (aModel); ShapeView_VisibilityState* aVisibilityState = new ShapeView_VisibilityState (aModel); aModel->SetVisibilityState (aVisibilityState); TreeModel_Tools::UseVisibilityColumn (myTreeView); QItemSelectionModel* aSelModel = new QItemSelectionModel (myTreeView->model(), myTreeView); myTreeView->setSelectionModel (aSelModel); connect (aSelModel, SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT (onTreeViewSelectionChanged (const QItemSelection&, const QItemSelection&))); QModelIndex aParentIndex = myTreeView->model()->index (0, 0); myTreeView->setExpanded (aParentIndex, true); myMainWindow->setCentralWidget (myTreeView); // property view //myPaneCreators.Append (new VInspectorPaneAIS_PaneCreator()); myPropertyView = new ViewControl_PropertyView (myMainWindow, QSize(SHAPEVIEW_DEFAULT_VIEW_WIDTH, SHAPEVIEW_DEFAULT_VIEW_HEIGHT)); myPropertyPanelWidget = new QDockWidget (tr ("PropertyPanel"), myMainWindow); myPropertyPanelWidget->setObjectName (myPropertyPanelWidget->windowTitle()); myPropertyPanelWidget->setTitleBarWidget (new QWidget(myMainWindow)); myPropertyPanelWidget->setWidget (myPropertyView->GetControl()); myMainWindow->addDockWidget (Qt::RightDockWidgetArea, myPropertyPanelWidget); // view myViewWindow = new View_Window (myMainWindow, NULL, false); connect (myViewWindow, SIGNAL(eraseAllPerformed()), this, SLOT(onEraseAllPerformed())); aVisibilityState->SetDisplayer (myViewWindow->GetDisplayer()); aVisibilityState->SetPresentationType (View_PresentationType_Main); myViewWindow->GetView()->SetPredefinedSize (SHAPEVIEW_DEFAULT_VIEW_WIDTH, SHAPEVIEW_DEFAULT_VIEW_HEIGHT); QDockWidget* aViewDockWidget = new QDockWidget (tr ("View"), myMainWindow); aViewDockWidget->setObjectName (aViewDockWidget->windowTitle()); aViewDockWidget->setWidget (myViewWindow); aViewDockWidget->setTitleBarWidget (myViewWindow->GetViewToolBar()->GetControl()); myMainWindow->addDockWidget (Qt::RightDockWidgetArea, aViewDockWidget); myMainWindow->splitDockWidget(myPropertyPanelWidget, aViewDockWidget, Qt::Vertical); myMainWindow->resize (DEFAULT_SHAPE_VIEW_WIDTH, DEFAULT_SHAPE_VIEW_HEIGHT); myMainWindow->move (DEFAULT_SHAPE_VIEW_POSITION_X, DEFAULT_SHAPE_VIEW_POSITION_Y); } // ======================================================================= // function : Destructor // purpose : // ======================================================================= ShapeView_Window::~ShapeView_Window() { onCloseAllBREPViews(); } // ======================================================================= // function : SetParent // purpose : // ======================================================================= void ShapeView_Window::SetParent (void* theParent) { QWidget* aParent = (QWidget*)theParent; if (aParent) { QLayout* aLayout = aParent->layout(); if (aLayout) aLayout->addWidget (GetMainWindow()); } } // ======================================================================= // function : FillActionsMenu // purpose : // ======================================================================= void ShapeView_Window::FillActionsMenu (void* theMenu) { QMenu* aMenu = (QMenu*)theMenu; QList aDockwidgets = myMainWindow->findChildren(); for (QList::iterator it = aDockwidgets.begin(); it != aDockwidgets.end(); ++it) { QDockWidget* aDockWidget = *it; if (aDockWidget->parentWidget() == myMainWindow) aMenu->addAction (aDockWidget->toggleViewAction()); } } // ======================================================================= // function : GetPreferences // purpose : // ======================================================================= void ShapeView_Window::GetPreferences (TInspectorAPI_PreferencesDataMap& theItem) { theItem.Bind ("geometry", TreeModel_Tools::ToString (myMainWindow->saveState()).toStdString().c_str()); QMap anItems; TreeModel_Tools::SaveState (myTreeView, anItems); View_Tools::SaveState(myViewWindow, anItems); for (QMap::const_iterator anItemsIt = anItems.begin(); anItemsIt != anItems.end(); anItemsIt++) theItem.Bind (anItemsIt.key().toStdString().c_str(), anItemsIt.value().toStdString().c_str()); } // ======================================================================= // function : SetPreferences // purpose : // ======================================================================= void ShapeView_Window::SetPreferences (const TInspectorAPI_PreferencesDataMap& theItem) { if (theItem.IsEmpty()) { TreeModel_Tools::SetDefaultHeaderSections (myTreeView); return; } for (TInspectorAPI_IteratorOfPreferencesDataMap anItemIt (theItem); anItemIt.More(); anItemIt.Next()) { if (anItemIt.Key().IsEqual ("geometry")) myMainWindow->restoreState (TreeModel_Tools::ToByteArray (anItemIt.Value().ToCString())); else if (TreeModel_Tools::RestoreState (myTreeView, anItemIt.Key().ToCString(), anItemIt.Value().ToCString())) continue; else if (View_Tools::RestoreState(myViewWindow, anItemIt.Key().ToCString(), anItemIt.Value().ToCString())) continue; } } // ======================================================================= // function : UpdateContent // purpose : // ======================================================================= void ShapeView_Window::UpdateContent() { TCollection_AsciiString aName = "TKShapeView"; if (myParameters->FindParameters (aName)) { NCollection_List aParameters = myParameters->Parameters (aName); // Init will remove from parameters those, that are processed only one time (TShape) Init(aParameters); myParameters->SetParameters (aName, aParameters); } if (myParameters->FindFileNames(aName)) { for (NCollection_List::Iterator aFilesIt(myParameters->FileNames(aName)); aFilesIt.More(); aFilesIt.Next()) OpenFile (aFilesIt.Value()); NCollection_List aNames; myParameters->SetFileNames (aName, aNames); } // make TopoDS_TShape selected if exist in select parameters NCollection_List anObjects; if (myParameters->GetSelectedObjects(aName, anObjects)) { ShapeView_TreeModel* aModel = dynamic_cast (myTreeView->model()); QItemSelectionModel* aSelectionModel = myTreeView->selectionModel(); aSelectionModel->clear(); for (NCollection_List::Iterator aParamsIt (anObjects); aParamsIt.More(); aParamsIt.Next()) { Handle(Standard_Transient) anObject = aParamsIt.Value(); Handle(TopoDS_TShape) aShapePointer = Handle(TopoDS_TShape)::DownCast (anObject); if (aShapePointer.IsNull()) continue; TopoDS_Shape aShape; aShape.TShape (aShapePointer); QModelIndex aShapeIndex = aModel->FindIndex (aShape); if (!aShapeIndex.isValid()) continue; aSelectionModel->select (aShapeIndex, QItemSelectionModel::Select); myTreeView->scrollTo (aShapeIndex); } myParameters->SetSelected (aName, NCollection_List()); } } // ======================================================================= // function : Init // purpose : // ======================================================================= void ShapeView_Window::Init (NCollection_List& theParameters) { Handle(AIS_InteractiveContext) aContext; NCollection_List aParameters; TCollection_AsciiString aPluginName ("TKShapeView"); NCollection_List aSelectedParameters; if (myParameters->FindSelectedNames (aPluginName)) // selected names have TShape parameters aSelectedParameters = myParameters->GetSelectedNames (aPluginName); NCollection_List::Iterator aParamsIt (aSelectedParameters); for (NCollection_List::Iterator anObjectsIt (theParameters); anObjectsIt.More(); anObjectsIt.Next()) { Handle(Standard_Transient) anObject = anObjectsIt.Value(); Handle(TopoDS_TShape) aShapePointer = Handle(TopoDS_TShape)::DownCast (anObject); if (!aShapePointer.IsNull()) { TopoDS_Shape aShape; aShape.TShape (aShapePointer); if (aParamsIt.More()) { // each Transient object has own location/orientation description TInspectorAPI_PluginParameters::ParametersToShape (aParamsIt.Value(), aShape); aParamsIt.Next(); } addShape (aShape); } else { aParameters.Append (anObject); if (aContext.IsNull()) aContext = Handle(AIS_InteractiveContext)::DownCast (anObject); } } if (!aContext.IsNull()) myViewWindow->SetContext (View_ContextType_External, aContext); theParameters = aParameters; myParameters->SetSelectedNames (aPluginName, NCollection_List()); } // ======================================================================= // function : OpenFile // purpose : // ======================================================================= void ShapeView_Window::OpenFile(const TCollection_AsciiString& theFileName) { TopoDS_Shape aShape = ShapeView_Tools::ReadShape (theFileName); if (!aShape.IsNull()) addShape(aShape); } // ======================================================================= // function : RemoveAllShapes // purpose : // ======================================================================= void ShapeView_Window::RemoveAllShapes() { ShapeView_TreeModel* aModel = dynamic_cast (myTreeView->model()); aModel->RemoveAllShapes(); onCloseAllBREPViews(); } // ======================================================================= // function : addShape // purpose : // ======================================================================= void ShapeView_Window::addShape (const TopoDS_Shape& theShape) { ShapeView_TreeModel* aModel = dynamic_cast (myTreeView->model()); aModel->AddShape (theShape); } // ======================================================================= // function : onTreeViewContextMenuRequested // purpose : // ======================================================================= void ShapeView_Window::onTreeViewContextMenuRequested (const QPoint& thePosition) { QItemSelectionModel* aModel = myTreeView->selectionModel(); if (!aModel) return; QModelIndex anIndex = TreeModel_ModelBase::SingleSelected (aModel->selectedIndexes(), 0); TreeModel_ItemBasePtr anItemBase = TreeModel_ModelBase::GetItemByIndex (anIndex); if (!anItemBase) return; QMenu* aMenu = new QMenu(myMainWindow); ShapeView_ItemRootPtr aRootItem = itemDynamicCast (anItemBase); if (aRootItem) { aMenu->addAction (ViewControl_Tools::CreateAction ("Load BREP file", SLOT (onLoadFile()), myMainWindow, this)); aMenu->addAction (ViewControl_Tools::CreateAction ("Remove all shape items", SLOT (onClearView()), myMainWindow, this)); } else { if (!GetTemporaryDirectory().IsEmpty()) aMenu->addAction (ViewControl_Tools::CreateAction ("BREP view", SLOT (onBREPView()), myMainWindow, this)); aMenu->addAction (ViewControl_Tools::CreateAction ("Close All BREP views", SLOT (onCloseAllBREPViews()), myMainWindow, this)); aMenu->addAction (ViewControl_Tools::CreateAction ("BREP directory", SLOT (onBREPDirectory()), myMainWindow, this)); aMenu->addAction (ViewControl_Tools::CreateAction ("ShapeFix_Shape", SLOT (onShapeFixShape()), myMainWindow, this)); ShapeView_ItemShapePtr aShapeItem = itemDynamicCast(anItemBase); const TopoDS_Shape& aShape = aShapeItem->GetItemShape(); TopAbs_ShapeEnum anExplodeType = aShapeItem->GetExplodeType(); NCollection_List anExplodeTypes; ShapeView_Tools::IsPossibleToExplode (aShape, anExplodeTypes); if (anExplodeTypes.Size() > 0) { QMenu* anExplodeMenu = aMenu->addMenu ("Explode"); for (NCollection_List::Iterator anExpIterator (anExplodeTypes); anExpIterator.More(); anExpIterator.Next()) { TopAbs_ShapeEnum aType = anExpIterator.Value(); QAction* anAction = ViewControl_Tools::CreateAction (TopAbs::ShapeTypeToString (aType), SLOT (onExplode()), myMainWindow, this); anExplodeMenu->addAction (anAction); if (anExplodeType == aType) { anAction->setCheckable (true); anAction->setChecked (true); } } QAction* anAction = ViewControl_Tools::CreateAction ("NONE", SLOT (onExplode()), myMainWindow, this); anExplodeMenu->addSeparator(); anExplodeMenu->addAction (anAction); } } QPoint aPoint = myTreeView->mapToGlobal (thePosition); aMenu->exec (aPoint); } // ======================================================================= // function : // onTreeViewSelectionChanged // purpose : // ======================================================================= void ShapeView_Window::onTreeViewSelectionChanged (const QItemSelection&, const QItemSelection&) { QApplication::setOverrideCursor (Qt::WaitCursor); if (myPropertyPanelWidget->toggleViewAction()->isChecked()) updatePropertyPanelBySelection(); QApplication::restoreOverrideCursor(); } // ======================================================================= // function : onEraseAllPerformed // purpose : // ======================================================================= void ShapeView_Window::onEraseAllPerformed() { ShapeView_TreeModel* aTreeModel = dynamic_cast (myTreeView->model()); // TODO: provide update for only visibility state for better performance TopoDS_Shape myCustomShape; aTreeModel->Reset(); aTreeModel->EmitLayoutChanged(); } // ======================================================================= // function : onBREPDirectory // purpose : // ======================================================================= void ShapeView_Window::onBREPDirectory() { QString aFilter (tr ("BREP file (*.brep*)")); QString aSelectedFilter; QString aFileName = QFileDialog::getOpenFileName (0, tr ("Export shape to BREP file"), GetTemporaryDirectory().ToCString(), aSelectedFilter); if (!aFileName.isEmpty()) viewFile (aFileName); } // ======================================================================= // function : onExplode // purpose : // ======================================================================= void ShapeView_Window::onShapeFixShape() { QItemSelectionModel* aModel = myTreeView->selectionModel(); if (!aModel) return; QModelIndex anIndex = TreeModel_ModelBase::SingleSelected(aModel->selectedIndexes(), 0); TreeModel_ItemBasePtr anItemBase = TreeModel_ModelBase::GetItemByIndex(anIndex); if (!anItemBase) return; ShapeView_ItemShapePtr aShapeItem = itemDynamicCast(anItemBase); if (!aShapeItem) return; const TopoDS_Shape aShape = aShapeItem->GetItemShape(); Standard_Real LinTol = Precision::Confusion(); Standard_Real AngTol = Precision::Angular(); Handle(ShapeFix_Shape) Fixer = new ShapeFix_Shape (aShape); Fixer->SetPrecision (LinTol); Fixer->SetMaxTolerance (LinTol); Fixer->Perform(); TopoDS_Shape aFixedShape = Fixer->Shape(); addShape (aFixedShape); } // ======================================================================= // function : onExplode // purpose : // ======================================================================= void ShapeView_Window::onExplode() { QItemSelectionModel* aModel = myTreeView->selectionModel(); if (!aModel) return; QModelIndex anIndex = TreeModel_ModelBase::SingleSelected(aModel->selectedIndexes(), 0); TreeModel_ItemBasePtr anItemBase = TreeModel_ModelBase::GetItemByIndex(anIndex); if (!anItemBase) return; ShapeView_ItemShapePtr aShapeItem = itemDynamicCast(anItemBase); if (!aShapeItem) return; QAction* anAction = (QAction*)sender(); if (!anAction) return; QApplication::setOverrideCursor (Qt::WaitCursor); TopAbs_ShapeEnum aShapeType; if (anAction->text() == "NONE") aShapeType = TopAbs_SHAPE; else aShapeType = TopAbs::ShapeTypeFromString(anAction->text().toStdString().c_str()); myViewWindow->GetDisplayer()->EraseAllPresentations(); aShapeItem->SetExplodeType(aShapeType); //anItemBase->Parent()->Reset(); - TODO (update only modified sub-tree) ShapeView_TreeModel* aTreeModel = dynamic_cast (myTreeView->model()); aTreeModel->Reset(); aTreeModel->EmitLayoutChanged(); QApplication::restoreOverrideCursor(); } // ======================================================================= // function : onLoadFile // purpose : // ======================================================================= void ShapeView_Window::onLoadFile() { QString aDataDirName = QDir::currentPath(); QString aFileName = ShapeView_OpenFileDialog::OpenFile(0, aDataDirName); aFileName = QDir().toNativeSeparators (aFileName); if (aFileName.isEmpty()) return; QApplication::setOverrideCursor (Qt::WaitCursor); onOpenFile(aFileName); QApplication::restoreOverrideCursor(); } // ======================================================================= // function : onBREPView // purpose : // ======================================================================= void ShapeView_Window::onBREPView() { if (GetTemporaryDirectory().IsEmpty()) return; QItemSelectionModel* aModel = myTreeView->selectionModel(); if (!aModel) return; QModelIndexList aSelectedRows = aModel->selectedRows(); if (aSelectedRows.size() == 0) return; QModelIndex aSelectedIndex = aSelectedRows.at (0); TreeModel_ItemBasePtr anItemBase = TreeModel_ModelBase::GetItemByIndex (aSelectedIndex); if (!anItemBase) return; ShapeView_ItemShapePtr anItem = itemDynamicCast(anItemBase); if (!anItem) return; QString aFileName = anItem->GetFileName(); QDir aDir; if (aFileName.isEmpty() || !aDir.exists (aFileName)) { TCollection_AsciiString aFileNameIndiced = GetTemporaryDirectory() + TCollection_AsciiString ("\\") + getNextTmpName (anItem->TShapePointer()); const TopoDS_Shape& aShape = anItem->GetItemShape(); BRepTools::Write (aShape, aFileNameIndiced.ToCString()); anItem->SetFileName (aFileNameIndiced.ToCString()); aFileName = aFileNameIndiced.ToCString(); } viewFile (aFileName); } // ======================================================================= // function : onCloseAllBREPViews // purpose : // ======================================================================= void ShapeView_Window::onCloseAllBREPViews() { removeBREPFiles(); for (int aViewId = myBREPViews.size()-1; aViewId >= 0; aViewId--) delete myBREPViews[aViewId]; myBREPViews.clear(); } // ======================================================================= // function : onEditorDestroyed // purpose : // ======================================================================= void ShapeView_Window::onEditorDestroyed(QObject* theObject) { QWidget* aWidget = dynamic_cast (theObject); for (int aViewId = myBREPViews.size()-1; aViewId >= 0; aViewId--) { if (myBREPViews[aViewId] == aWidget) myBREPViews.removeAll(aWidget); } } // ======================================================================= // function : viewFile // purpose : // ======================================================================= void ShapeView_Window::viewFile (const QString& theFileName) { QApplication::setOverrideCursor (Qt::WaitCursor); QString aFileText; QFile aFile (theFileName); if (aFile.open (QIODevice::ReadOnly | QIODevice::Text)) { QTextStream aStream(&aFile); QString aLine = aStream.readLine(); while (!aLine.isNull()) { aLine = aStream.readLine(); aFileText.append (aLine + QString ("\n")); } if (!aFileText.isEmpty()) { QPlainTextEdit* anEditor = new QPlainTextEdit (0); anEditor->setAttribute (Qt::WA_DeleteOnClose, true); connect (anEditor, SIGNAL (destroyed(QObject*)), this, SLOT (onEditorDestroyed(QObject*))); anEditor->setPlainText (aFileText); anEditor->resize (DEFAULT_TEXT_VIEW_WIDTH, DEFAULT_TEXT_VIEW_HEIGHT); anEditor->move (DEFAULT_TEXT_VIEW_POSITION_X + myNextPosition, DEFAULT_TEXT_VIEW_POSITION_Y); myNextPosition += DEFAULT_TEXT_VIEW_DELTA; anEditor->show(); myBREPViews.append (anEditor); } } QApplication::restoreOverrideCursor(); } // ======================================================================= // function : updatePropertyPanelBySelection // purpose : // ======================================================================= void ShapeView_Window::updatePropertyPanelBySelection() { QItemSelectionModel* aModel = myTreeView->selectionModel(); if (!aModel) return; QModelIndexList aSelected = TreeModel_ModelBase::GetSelected (aModel->selectedIndexes(), 0); QList aTableValues; if (aSelected.size() == 1) { TreeModel_ItemBasePtr aSelectedItem = TreeModel_ModelBase::GetItemByIndex(aSelected.first()); ShapeView_Tools::GetPropertyTableValues (aSelectedItem, aTableValues); } myPropertyView->Init (aTableValues); } // ======================================================================= // function : removeBREPFiles // purpose : // ======================================================================= void ShapeView_Window::removeBREPFiles() { QDir aDir (GetTemporaryDirectory().ToCString()); QStringList anEntries = aDir.entryList(); QString aPrefix(viewBREPPrefix().ToCString()); for (int anEntryId = 0, aSize = anEntries.size(); anEntryId < aSize; anEntryId++) { if (anEntries[anEntryId].contains (aPrefix)) aDir.remove (anEntries[anEntryId]); } } // ======================================================================= // function : getNextTmpName // purpose : // ======================================================================= TCollection_AsciiString ShapeView_Window::getNextTmpName (const TCollection_AsciiString& thePointerInfo) { TCollection_AsciiString aTmpName(viewBREPPrefix()); aTmpName += thePointerInfo; return aTmpName; }