From: azv Date: Mon, 28 Oct 2019 11:02:32 +0000 (+0300) Subject: Task 5.1.7: To be able to export a part to a file and import it into an existing... X-Git-Tag: V9_5_0a1~166^2~25 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=76b92ca1a1dce1aa3e0561f4213510232df1efc2;p=modules%2Fshaper.git Task 5.1.7: To be able to export a part to a file and import it into an existing part (issue #3065) Implement exporting/importing of the part to binary file. --- diff --git a/src/ExchangePlugin/CMakeLists.txt b/src/ExchangePlugin/CMakeLists.txt index 222f2e6ea..4094385a5 100644 --- a/src/ExchangePlugin/CMakeLists.txt +++ b/src/ExchangePlugin/CMakeLists.txt @@ -37,6 +37,8 @@ SET(PROJECT_HEADERS ExchangePlugin_Validators.h ExchangePlugin_Tools.h ExchangePlugin_Dump.h + ExchangePlugin_ImportPart.h + ExchangePlugin_ExportPart.h ) SET(PROJECT_SOURCES @@ -46,6 +48,8 @@ SET(PROJECT_SOURCES ExchangePlugin_Validators.cpp ExchangePlugin_Tools.cpp ExchangePlugin_Dump.cpp + ExchangePlugin_ImportPart.cpp + ExchangePlugin_ExportPart.cpp ) SET(XML_RESOURCES diff --git a/src/ExchangePlugin/ExchangePlugin_ExportPart.cpp b/src/ExchangePlugin/ExchangePlugin_ExportPart.cpp new file mode 100644 index 000000000..dbf476c2f --- /dev/null +++ b/src/ExchangePlugin/ExchangePlugin_ExportPart.cpp @@ -0,0 +1,154 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#include + +#include +#include +#include +#include +#include + +// Obtain all features to be exported to get the list of selected results. +static void collectFeatures(AttributeSelectionListPtr theSelected, + std::list& theExport); +// Obtain all constuction elements of the document. +static void collectConstructions(DocumentPtr theDocument, std::list& theExport); + + +ExchangePlugin_ExportPart::ExchangePlugin_ExportPart() +{ +} + +void ExchangePlugin_ExportPart::initAttributes() +{ + data()->addAttribute(FILE_PATH_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(FILE_FORMAT_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(SELECTION_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SELECTION_LIST_ID()); +} + +void ExchangePlugin_ExportPart::execute() +{ + AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID()); + std::string aFilename = aFilePathAttr->value(); + if (aFilename.empty()) { + setError("File path is empty."); + return; + } + + std::list aFeaturesToExport; + + SessionPtr aSession = ModelAPI_Session::get(); + AttributeSelectionListPtr aSelected = selectionList(SELECTION_LIST_ID()); + DocumentPtr anExportDoc; + if (aSelected && aSelected->size() == 0 && + aSession->activeDocument() == aSession->moduleDocument()) { + // no result is selected, thus have to export all features of the current document, + // but the document is a PartSet; and it is forbidden to copy results of Parts, + // thus copy construction elements only + collectConstructions(aSession->moduleDocument(), aFeaturesToExport); + } + else + collectFeatures(aSelected, aFeaturesToExport); + + if (!aFeaturesToExport.empty()) { + // remove 'ExportPart' feature is any + if (aFeaturesToExport.back()->getKind() == ExchangePlugin_ExportPart::ID()) + aFeaturesToExport.pop_back(); + // save the document + if (!aSession->activeDocument()->save(aFilename.c_str(), aFeaturesToExport)) + setError("Cannot save the document."); + } +} + + +// ================================ Auxiliary functions =================================== + +static void allReferencedFeatures(std::set& theFeatures) +{ + std::set aReferences; + for (std::set::iterator anIt = theFeatures.begin(); + anIt != theFeatures.end(); ++anIt) { + std::list > > aRefs; + (*anIt)->data()->referencesToObjects(aRefs); + + for (std::list > >::iterator aRIt = aRefs.begin(); + aRIt != aRefs.end(); ++aRIt) { + for (std::list::iterator anObjIt = aRIt->second.begin(); + anObjIt != aRIt->second.end(); ++anObjIt) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt); + if (aFeature) + aReferences.insert(aFeature); + } + } + } + + if (!aReferences.empty()) { + allReferencedFeatures(aReferences); + theFeatures.insert(aReferences.begin(), aReferences.end()); + } +} + +void collectFeatures(AttributeSelectionListPtr theSelected, std::list& theExport) +{ + theExport = ModelAPI_Session::get()->activeDocument()->allFeatures(); + + if (!theSelected || theSelected->size() == 0) { + // nothing is selected, return all features of the document + return; + } + + // collect initial list of features basing on the selected results + std::set aFeaturesToExport; + for (int anIndex = 0, aSize = theSelected->size(); anIndex < aSize; ++anIndex) { + AttributeSelectionPtr aCurrent = theSelected->value(anIndex); + FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aCurrent->context()); + if (aCurrentFeature) + aFeaturesToExport.insert(aCurrentFeature); + } + // recursively collect all features used for the selected results + allReferencedFeatures(aFeaturesToExport); + + // remove the features which are not affect the selected results + std::list::iterator anIt = theExport.begin(); + while (anIt != theExport.end()) { + if (aFeaturesToExport.find(*anIt) == aFeaturesToExport.end()) { + std::list::iterator aRemoveIt = anIt++; + theExport.erase(aRemoveIt); + } + else + ++anIt; + } +} + +void collectConstructions(DocumentPtr theDocument, std::list& theExport) +{ + theExport = theDocument->allFeatures(); + // keep constructions only + std::list::iterator anIt = theExport.begin(); + while (anIt != theExport.end()) { + if ((*anIt)->lastResult()->groupName() == ModelAPI_ResultConstruction::group()) + ++anIt; + else { + std::list::iterator aRemoveIt = anIt++; + theExport.erase(aRemoveIt); + } + } +} diff --git a/src/ExchangePlugin/ExchangePlugin_ExportPart.h b/src/ExchangePlugin/ExchangePlugin_ExportPart.h new file mode 100644 index 000000000..504d777f8 --- /dev/null +++ b/src/ExchangePlugin/ExchangePlugin_ExportPart.h @@ -0,0 +1,84 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#ifndef EXCHANGEPLUGIN_EXPORTPART_H_ +#define EXCHANGEPLUGIN_EXPORTPART_H_ + +#include +#include + +/** + * \class ExchangePlugin_ExportPart + * \ingroup Plugins + * \brief Feature for export some results of a Part to the binary format for the further import. + */ +class ExchangePlugin_ExportPart : public ModelAPI_Feature +{ +public: + /// Feature kind + inline static const std::string& ID() + { + static const std::string MY_EXPORT_ID("ExportPart"); + return MY_EXPORT_ID; + } + /// attribute name of file path + inline static const std::string& FILE_PATH_ID() + { + static const std::string MY_FILE_PATH_ID("file_path"); + return MY_FILE_PATH_ID; + } + /// attribute name of file format + inline static const std::string& FILE_FORMAT_ID() + { + static const std::string MY_FILE_FORMAT_ID("file_format"); + return MY_FILE_FORMAT_ID; + } + /// attribute name of selection list + inline static const std::string& SELECTION_LIST_ID() + { + static const std::string MY_SELECTION_LIST_ID("selection_list"); + return MY_SELECTION_LIST_ID; + } + /// Default constructor + ExchangePlugin_ExportPart(); + + /// Returns the unique kind of a feature + EXCHANGEPLUGIN_EXPORT virtual const std::string& getKind() + { + return ExchangePlugin_ExportPart::ID(); + } + + /// Request for initialization of data model of the feature: adding all attributes + EXCHANGEPLUGIN_EXPORT virtual void initAttributes(); + + /// Computes or recomputes the results + EXCHANGEPLUGIN_EXPORT virtual void execute(); + + /// Returns true if this feature is used as macro: creates other features and then removed. + EXCHANGEPLUGIN_EXPORT virtual bool isMacro() const { return true; } + + /// Reimplemented from ModelAPI_Feature::isPreviewNeeded(). Returns false. + EXCHANGEPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; } + + /// Do not put in history. + /// Since it is not a macro, it is not deleted, but we don't want to see it. + bool isInHistory() { return false; } +}; + +#endif /* EXCHANGEPLUGIN_EXPORTPART_H_ */ diff --git a/src/ExchangePlugin/ExchangePlugin_ImportPart.cpp b/src/ExchangePlugin/ExchangePlugin_ImportPart.cpp new file mode 100644 index 000000000..ed0c456b7 --- /dev/null +++ b/src/ExchangePlugin/ExchangePlugin_ImportPart.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#include + +#include +#include + +ExchangePlugin_ImportPart::ExchangePlugin_ImportPart() +{ +} + +void ExchangePlugin_ImportPart::initAttributes() +{ + data()->addAttribute(FILE_PATH_ID(), ModelAPI_AttributeString::typeId()); +} + +void ExchangePlugin_ImportPart::execute() +{ + AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID()); + std::string aFilename = aFilePathAttr->value(); + if (aFilename.empty()) { + setError("File path is empty."); + return; + } + + // load the file into the active document + SessionPtr aSession = ModelAPI_Session::get(); + if (!aSession->activeDocument()->import(aFilename.c_str())) + setError("Cannot import the document."); +} diff --git a/src/ExchangePlugin/ExchangePlugin_ImportPart.h b/src/ExchangePlugin/ExchangePlugin_ImportPart.h new file mode 100644 index 000000000..b10ba54d7 --- /dev/null +++ b/src/ExchangePlugin/ExchangePlugin_ImportPart.h @@ -0,0 +1,68 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#ifndef EXCHANGEPLUGIN_IMPORTPART_H_ +#define EXCHANGEPLUGIN_IMPORTPART_H_ + +#include +#include + +/** + * \class ExchangePlugin_ImportPart + * \ingroup Plugins + * \brief Feature for import the structure of Part into the current document. + */ +class ExchangePlugin_ImportPart : public ModelAPI_Feature +{ +public: + /// Feature kind + inline static const std::string& ID() + { + static const std::string MY_IMPORT_ID("ImportPart"); + return MY_IMPORT_ID; + } + /// attribute name of file path + inline static const std::string& FILE_PATH_ID() + { + static const std::string MY_FILE_PATH_ID("file_path"); + return MY_FILE_PATH_ID; + } + /// Default constructor + ExchangePlugin_ImportPart(); + + /// Returns the unique kind of a feature + EXCHANGEPLUGIN_EXPORT virtual const std::string& getKind() + { + return ExchangePlugin_ImportPart::ID(); + } + + /// Request for initialization of data model of the feature: adding all attributes + EXCHANGEPLUGIN_EXPORT virtual void initAttributes(); + + /// Computes or recomputes the results + EXCHANGEPLUGIN_EXPORT virtual void execute(); + + /// Returns true if this feature is used as macro: creates other features and then removed. + EXCHANGEPLUGIN_EXPORT virtual bool isMacro() const { return true; } + + /// Reimplemented from ModelAPI_Feature::isPreviewNeeded(). Returns false. + EXCHANGEPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; } +}; + +#endif /* EXCHANGEPLUGIN_IMPORTPART_H_ */ diff --git a/src/ExchangePlugin/ExchangePlugin_Plugin.cpp b/src/ExchangePlugin/ExchangePlugin_Plugin.cpp index 34c3c1b61..3d07a73cd 100644 --- a/src/ExchangePlugin/ExchangePlugin_Plugin.cpp +++ b/src/ExchangePlugin/ExchangePlugin_Plugin.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -53,6 +55,12 @@ FeaturePtr ExchangePlugin_Plugin::createFeature(std::string theFeatureID) if (theFeatureID == ExchangePlugin_ExportFeature::ID()) { return FeaturePtr(new ExchangePlugin_ExportFeature); } else + if (theFeatureID == ExchangePlugin_ImportPart::ID()) { + return FeaturePtr(new ExchangePlugin_ImportPart); + } else + if (theFeatureID == ExchangePlugin_ExportPart::ID()) { + return FeaturePtr(new ExchangePlugin_ExportPart); + } else if (theFeatureID == ExchangePlugin_Dump::ID()) { return FeaturePtr(new ExchangePlugin_Dump); } diff --git a/src/ExchangePlugin/icons/export_part.png b/src/ExchangePlugin/icons/export_part.png new file mode 100644 index 000000000..98e423e43 Binary files /dev/null and b/src/ExchangePlugin/icons/export_part.png differ diff --git a/src/ExchangePlugin/icons/import_part.png b/src/ExchangePlugin/icons/import_part.png new file mode 100644 index 000000000..8443bd178 Binary files /dev/null and b/src/ExchangePlugin/icons/import_part.png differ diff --git a/src/ExchangePlugin/plugin-Exchange.xml b/src/ExchangePlugin/plugin-Exchange.xml index 59a246ecd..8b8cd1a1d 100644 --- a/src/ExchangePlugin/plugin-Exchange.xml +++ b/src/ExchangePlugin/plugin-Exchange.xml @@ -33,6 +33,29 @@ tooltip="To use geometrical order for identification of selected shapes" default="false"/> --> + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Model/CMakeLists.txt b/src/Model/CMakeLists.txt index 554b8c03a..348761424 100644 --- a/src/Model/CMakeLists.txt +++ b/src/Model/CMakeLists.txt @@ -53,6 +53,7 @@ SET(PROJECT_HEADERS Model_ResultField.h Model_ResultGroup.h Model_ResultParameter.h + Model_Tools.h Model_Update.h Model_Validator.h ) @@ -90,6 +91,7 @@ SET(PROJECT_SOURCES Model_ResultField.cpp Model_ResultGroup.cpp Model_ResultParameter.cpp + Model_Tools.cpp Model_Update.cpp Model_Validator.cpp ) diff --git a/src/Model/Model_Application.cpp b/src/Model/Model_Application.cpp index 6cfb6a3a3..0d5e6eeb0 100644 --- a/src/Model/Model_Application.cpp +++ b/src/Model/Model_Application.cpp @@ -22,6 +22,8 @@ #include +#include + IMPLEMENT_STANDARD_RTTIEXT(Model_Application, TDocStd_Application) static Handle_Model_Application TheApplication = new Model_Application; @@ -168,6 +170,14 @@ Model_Application::Model_Application() // store handle to the application to avoid nullification static Handle(Model_Application) TheKeepHandle; TheKeepHandle = this; + // additional file format supported + static TCollection_ExtendedString THE_DOC_FORMAT("BinOcaf"/*"BinShaperPart"*/); + static TCollection_ExtendedString THE_FILE_EXT("shaperpart"); + Handle(PCDM_RetrievalDriver) aReader = + Handle(PCDM_RetrievalDriver)::DownCast(TheKeepHandle->ReaderFromFormat("BinOcaf")); + Handle(PCDM_StorageDriver) aWriter = TheKeepHandle->WriterFromFormat("BinOcaf"); + TheKeepHandle->DefineFormat(THE_DOC_FORMAT, "Shaper Part document", THE_FILE_EXT, + aReader, aWriter); } //======================================================================= diff --git a/src/Model/Model_Data.cpp b/src/Model/Model_Data.cpp index 10d11678d..45798a12f 100644 --- a/src/Model/Model_Data.cpp +++ b/src/Model/Model_Data.cpp @@ -35,6 +35,9 @@ #include #include #include +#include +#include + #include #include #include @@ -43,7 +46,6 @@ #include #include #include -#include #include #include @@ -56,13 +58,8 @@ #include #include -#include #include -#include -#include -#include #include -#include #include @@ -797,37 +794,10 @@ void Model_Data::referencesToObjects( } } -/// makes copy of all attributes on the given label and all sub-labels -static void copyAttrs(TDF_Label theSource, TDF_Label theDestination) { - TDF_AttributeIterator anAttrIter(theSource); - for(; anAttrIter.More(); anAttrIter.Next()) { - Handle(TDF_Attribute) aTargetAttr; - if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) { - // create a new attribute if not yet exists in the destination - aTargetAttr = anAttrIter.Value()->NewEmpty(); - theDestination.AddAttribute(aTargetAttr); - } - // no special relocation, empty map, but self-relocation is on: copy references w/o changes - Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(Standard_True); - anAttrIter.Value()->Paste(aTargetAttr, aRelocTable); - // an exception: if a source reference refers itself, a copy must also refer itself - if (aTargetAttr->ID() == TDF_Reference::GetID()) { - Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr); - if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label())) - aTargetRef->Set(aTargetRef->Label()); - } - } - // copy the sub-labels content - TDF_ChildIterator aSubLabsIter(theSource); - for(; aSubLabsIter.More(); aSubLabsIter.Next()) { - copyAttrs(aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag())); - } -} - void Model_Data::copyTo(std::shared_ptr theTarget) { TDF_Label aTargetRoot = std::dynamic_pointer_cast(theTarget)->label(); - copyAttrs(myLab, aTargetRoot); + Model_Tools::copyAttrs(myLab, aTargetRoot); // reinitialize Model_Attributes by TDF_Attributes set std::shared_ptr aTData = std::dynamic_pointer_cast(theTarget); aTData->myAttrs.clear(); diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index be2877848..8773abc2a 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,7 @@ #include #include #include -#include +#include #include #include @@ -221,24 +222,20 @@ static void updateShapesFromRoot(const TDF_Label theThisAccess, const TDF_Label } // LCOV_EXCL_STOP -bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis) +static bool loadDocument(Handle(Model_Application) theApp, + Handle(TDocStd_Document)& theDoc, + const TCollection_ExtendedString& theFilename) { - Handle(Model_Application) anApp = Model_Application::getApplication(); - if (isRoot()) { - anApp->setLoadPath(theDirName); - } - TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName)); - PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1; - Handle(TDocStd_Document) aLoaded; + PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus)-1; try { - aStatus = anApp->Open(aPath, aLoaded); + aStatus = theApp->Open(theFilename, theDoc); } catch (Standard_Failure const& anException) { Events_InfoMessage("Model_Document", "Exception in opening of document: %1").arg(anException.GetMessageString()).send(); return false; } - bool isError = aStatus != PCDM_RS_OK; - if (isError) { + bool isOk = aStatus == PCDM_RS_OK; + if (!isOk) { // LCOV_EXCL_START switch (aStatus) { case PCDM_RS_UnknownDocument: @@ -296,9 +293,22 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum } // LCOV_EXCL_STOP } + return isOk; +} + +bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis) +{ + Handle(Model_Application) anApp = Model_Application::getApplication(); + if (isRoot()) { + anApp->setLoadPath(theDirName); + } + TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName)); + Handle(TDocStd_Document) aLoaded; + bool isOk = loadDocument(anApp, aLoaded, aPath); + std::shared_ptr aSession = std::dynamic_pointer_cast(Model_Session::get()); - if (!isError) { + if (isOk) { myDoc = aLoaded; myDoc->SetUndoLimit(UNDO_LIMIT); @@ -333,7 +343,89 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum } else { // open failed, but new document was created to work with it: inform the model aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false); } - return !isError; + return isOk; +} + +bool Model_Document::import(const char* theFileName) +{ + Handle(Model_Application) anApp = Model_Application::getApplication(); + TCollection_ExtendedString aFormat; + if (!anApp->Format(theFileName, aFormat)) + return false; + + Handle(TDocStd_Document) aTempDoc; + bool isOk = loadDocument(anApp, aTempDoc, theFileName); + + // copy features from the temporary document to the current + Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(Standard_True); + TDF_LabelList anAllNewFeatures; + // Perform the copying twice for correct references: + // 1. copy labels hierarchy and fill the relocation table + TDF_Label aMain = myDoc->Main(); + for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More(); anIt.Next()) { + TDF_Label aCurrentLab = anIt.Value(); + Handle(TDataStd_Comment) aFeatureID; + TDF_Label aNewFeatuerLab; + if (aCurrentLab.FindAttribute(TDataStd_Comment::GetID(), aFeatureID)) { + TCollection_AsciiString anID(aFeatureID->Get()); + FeaturePtr aNewFeature = addFeature(anID.ToCString()); + std::shared_ptr aData = + std::dynamic_pointer_cast(aNewFeature->data()); + aNewFeatuerLab = aData->label().Father(); + Model_Tools::copyLabels(aCurrentLab, aNewFeatuerLab, aRelocTable); + } + anAllNewFeatures.Append(aNewFeatuerLab); + } + // 2. copy attributes + TDF_ListIteratorOfLabelList aNewIt(anAllNewFeatures); + for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More(); anIt.Next()) { + TDF_Label aCurrentLab = anIt.Value(); + TDF_Label aFeatureLab = aNewIt.Value(); + if (aFeatureLab.IsNull()) + anAllNewFeatures.Remove(aNewIt); + else { + Model_Tools::copyAttrs(aCurrentLab, aFeatureLab, aRelocTable); + aNewIt.Next(); + } + } + + myObjs->synchronizeFeatures(anAllNewFeatures, true, false, false, true); + + if (aTempDoc->CanClose() == CDM_CCS_OK) + aTempDoc->Close(); + return isOk; +} + +static bool saveDocument(Handle(Model_Application) theApp, + Handle(TDocStd_Document) theDoc, + const TCollection_ExtendedString& theFilename) +{ + PCDM_StoreStatus aStatus; + try { + aStatus = theApp->SaveAs(theDoc, theFilename); + } + catch (Standard_Failure const& anException) { + Events_InfoMessage("Model_Document", + "Exception in saving of document: %1").arg(anException.GetMessageString()).send(); + return false; + } + bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj; + if (!isDone) { + switch (aStatus) { + case PCDM_SS_DriverFailure: + Events_InfoMessage("Model_Document", + "Can not save document: save driver-library failure").send(); + break; + case PCDM_SS_WriteFailure: + Events_InfoMessage("Model_Document", "Can not save document: file writing failure").send(); + break; + case PCDM_SS_Failure: + default: + Events_InfoMessage("Model_Document", "Can not save document").send(); + break; + } + } + return isDone; } bool Model_Document::save( @@ -374,34 +466,7 @@ bool Model_Document::save( } // filename in the dir is id of document inside of the given directory TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName)); - PCDM_StoreStatus aStatus; - try { - aStatus = anApp->SaveAs(myDoc, aPath); - } catch (Standard_Failure const& anException) { - Events_InfoMessage("Model_Document", - "Exception in saving of document: %1").arg(anException.GetMessageString()).send(); - if (aWasCurrent.get()) { // return the current feature to the initial position - setCurrentFeature(aWasCurrent, false); - aSession->setCheckTransactions(true); - } - return false; - } - bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj; - if (!isDone) { - switch (aStatus) { - case PCDM_SS_DriverFailure: - Events_InfoMessage("Model_Document", - "Can not save document: save driver-library failure").send(); - break; - case PCDM_SS_WriteFailure: - Events_InfoMessage("Model_Document", "Can not save document: file writing failure").send(); - break; - case PCDM_SS_Failure: - default: - Events_InfoMessage("Model_Document", "Can not save document").send(); - break; - } - } + bool isDone = saveDocument(anApp, myDoc, aPath); if (aWasCurrent.get()) { // return the current feature to the initial position setCurrentFeature(aWasCurrent, false); @@ -444,6 +509,41 @@ bool Model_Document::save( return isDone; } +bool Model_Document::save(const char* theFilename, + const std::list& theExportFeatures) const +{ + Handle(Model_Application) anApp = Model_Application::getApplication(); + TCollection_ExtendedString aFormat; + if (!anApp->Format(theFilename, aFormat)) + return false; + + Handle(TDocStd_Document) aTempDoc = new TDocStd_Document(aFormat); + TDF_Label aMain = aTempDoc->Main(); + + Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(Standard_True); + std::list::const_iterator anIt = theExportFeatures.begin(); + // Perform the copying twice for correct references: + // 1. copy labels hierarchy and fill the relocation table + for (; anIt != theExportFeatures.end(); ++anIt) { + TDF_Label aFeatureLab = aMain.NewChild(); + std::shared_ptr aData = std::dynamic_pointer_cast((*anIt)->data()); + Model_Tools::copyLabels(aData->label().Father(), aFeatureLab, aRelocTable); + } + // 2. copy attributes + TDF_ChildIterator aChildIt(aMain); + for (anIt = theExportFeatures.begin(); anIt != theExportFeatures.end(); ++anIt) { + TDF_Label aFeatureLab = aChildIt.Value(); + std::shared_ptr aData = std::dynamic_pointer_cast((*anIt)->data()); + Model_Tools::copyAttrs(aData->label().Father(), aFeatureLab, aRelocTable); + aChildIt.Next(); + } + + bool isDone = saveDocument(anApp, aTempDoc, theFilename); + if (aTempDoc->CanClose() == CDM_CCS_OK) + aTempDoc->Close(); + return isDone; +} + void Model_Document::close(const bool theForever) { std::shared_ptr aPM = Model_Session::get(); diff --git a/src/Model/Model_Document.h b/src/Model/Model_Document.h index 72a570738..2cf44cbd0 100644 --- a/src/Model/Model_Document.h +++ b/src/Model/Model_Document.h @@ -56,6 +56,12 @@ class Model_Document : public ModelAPI_Document MODEL_EXPORT virtual bool load( const char* theDirName, const char* theFileName, DocumentPtr theThis); + //! Loads the OCAF document from the file into the current document. + //! All the features are added after the active feature. + //! \param theFileName name of the file to import + //! \returns true if file was loaded successfully + MODEL_EXPORT virtual bool import(const char* theFileName); + //! Saves the OCAF document to the file. //! \param theDirName directory where the document will be saved //! \param theFileName a name of the document file to store @@ -64,6 +70,12 @@ class Model_Document : public ModelAPI_Document MODEL_EXPORT virtual bool save( const char* theDirName, const char* theFileName, std::list& theResults); + //! Export the list of features to the file + //! \param theFilename path to save the file + //! \param theExportFeatures list of features to export + MODEL_EXPORT virtual bool save(const char* theFilename, + const std::list >& theExportFeatures) const; + //! Removes document data //! \param theForever if it is false, document is just hidden //! (to keep possibility make it back on Undo/Redo) diff --git a/src/Model/Model_Tools.cpp b/src/Model/Model_Tools.cpp new file mode 100644 index 000000000..33bafd04d --- /dev/null +++ b/src/Model/Model_Tools.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#include + +#include + +#include +#include +#include +#include + +void Model_Tools::copyLabels(TDF_Label theSource, TDF_Label theDestination, + Handle(TDF_RelocationTable) theRelocTable) +{ + theRelocTable->SetRelocation(theSource, theDestination); + // copy the sub-labels hierarchy + TDF_ChildIterator aSubLabsIter(theSource); + for (; aSubLabsIter.More(); aSubLabsIter.Next()) { + copyLabels(aSubLabsIter.Value(), + theDestination.FindChild(aSubLabsIter.Value().Tag()), + theRelocTable); + } +} + +void Model_Tools::copyAttrs(TDF_Label theSource, TDF_Label theDestination, + Handle(TDF_RelocationTable) theRelocTable) +{ + TDF_AttributeIterator anAttrIter(theSource); + for(; anAttrIter.More(); anAttrIter.Next()) { + Handle(TDF_Attribute) aTargetAttr; + if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) { + // create a new attribute if not yet exists in the destination + aTargetAttr = anAttrIter.Value()->NewEmpty(); + theDestination.AddAttribute(aTargetAttr); + } + // no special relocation, empty map, but self-relocation is on: copy references w/o changes + Handle(TDF_RelocationTable) aRelocTable = + theRelocTable.IsNull() ? new TDF_RelocationTable(Standard_True) : theRelocTable; + anAttrIter.Value()->Paste(aTargetAttr, aRelocTable); + // an exception: if a source reference refers itself, a copy must also refer itself + if (aTargetAttr->ID() == TDF_Reference::GetID()) { + Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr); + if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label())) + aTargetRef->Set(aTargetRef->Label()); + } + } + // copy the sub-labels content + TDF_ChildIterator aSubLabsIter(theSource); + for(; aSubLabsIter.More(); aSubLabsIter.Next()) { + copyAttrs(aSubLabsIter.Value(), + theDestination.FindChild(aSubLabsIter.Value().Tag()), + theRelocTable); + } +} diff --git a/src/Model/Model_Tools.h b/src/Model/Model_Tools.h new file mode 100644 index 000000000..b1d79a50c --- /dev/null +++ b/src/Model/Model_Tools.h @@ -0,0 +1,41 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#ifndef Model_Tools_H_ +#define Model_Tools_H_ + +#include + +#include +#include + +/// A collection of methods useful for different parts of data model. +namespace Model_Tools +{ + /// makes copy of label and all its sub-labels without copying the attributes; + /// and feel the relocation table + void copyLabels(TDF_Label theSource, TDF_Label theDestination, + Handle(TDF_RelocationTable) theRelocTable); + + /// makes copy of all attributes on the given label and all sub-labels + void copyAttrs(TDF_Label theSource, TDF_Label theDestination, + Handle(TDF_RelocationTable) theRelocTable = Handle(TDF_RelocationTable)()); +}; + +#endif diff --git a/src/ModelAPI/ModelAPI_Document.h b/src/ModelAPI/ModelAPI_Document.h index 9cc95bad2..101910fc6 100644 --- a/src/ModelAPI/ModelAPI_Document.h +++ b/src/ModelAPI/ModelAPI_Document.h @@ -259,6 +259,18 @@ public: MODELAPI_EXPORT virtual std::shared_ptr nextFeature( std::shared_ptr theCurrent, const bool theReverse = false) const = 0; + /// Loads the OCAF document from the file into the current document. + /// All the features are added after the active feature. + /// \param theFileName name of the file to import + /// \returns true if file was loaded successfully + MODELAPI_EXPORT virtual bool import(const char* theFileName) = 0; + + /// Export the list of features to the file + /// \param theFilename path to save the file + /// \param theExportFeatures list of features to export + MODELAPI_EXPORT virtual bool save(const char* theFilename, + const std::list >& theExportFeatures) const = 0; + protected: //! Only for SWIG wrapping it is here MODELAPI_EXPORT ModelAPI_Document(); diff --git a/src/XGUI/CMakeLists.txt b/src/XGUI/CMakeLists.txt index cf51cc8b2..ac49c4ae1 100644 --- a/src/XGUI/CMakeLists.txt +++ b/src/XGUI/CMakeLists.txt @@ -199,6 +199,7 @@ ADD_DEFINITIONS( -DXGUI_EXPORTS ${OpenCASCADE_DEFINITIONS} -D_CRT_SECURE_NO_WARN SET(PROJECT_INCLUDES ${PROJECT_SOURCE_DIR}/src/Events ${PROJECT_SOURCE_DIR}/src/Config + ${PROJECT_SOURCE_DIR}/src/ExchangePlugin ${PROJECT_SOURCE_DIR}/src/ModelAPI ${PROJECT_SOURCE_DIR}/src/GeomAPI ${PROJECT_SOURCE_DIR}/src/ModuleBase diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index 3e552186d..8198f5f11 100644 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,9 @@ #include #include +#include +#include + #include #include @@ -183,6 +187,8 @@ static QString MyFilter2(QObject::tr("CAD Builder files (*.cadbld)")); static QString MyExtension(".cadbld"); #endif +static QString MyImportPartFilter(QObject::tr("Part files (*.shaperpart);;All files (*.*)")); + //****************************************************** XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) @@ -470,6 +476,19 @@ void XGUI_Workshop::initMenu() connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen())); salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE"); + aAction = salomeConnector()->addDesktopCommand("EXPORT_PART_CMD", tr("Export part..."), + tr("Export a part of the current document into a file"), + QIcon(), QKeySequence(), + false, "MEN_DESK_FILE"); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onExportPart())); + + aAction = salomeConnector()->addDesktopCommand("IMPORT_PART_CMD", tr("Import part..."), + tr("Import structure of a part"), + QIcon(), QKeySequence(), + false, "MEN_DESK_FILE"); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onImportPart())); + salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE"); + #else // File commands group AppElements_MenuGroupPanel* aGroup = myMainWindow->menuObject()->generalPage(); @@ -1243,6 +1262,42 @@ void XGUI_Workshop::onWidgetObjectUpdated() myDisplayer->updateViewer(); } +//****************************************************** +void XGUI_Workshop::onImportPart() +{ + if (!abortAllOperations()) + return; + + //show file dialog, check if readable and open + qreal aRatio = ModuleBase_Tools::currentPixelRatio(); + // If the ratio is > 1 (HD screen) then QT has a bug in + // displaying of system open file dialog (too small) + QString aFile = QFileDialog::getOpenFileName(desktop(), tr("Import part"), QString(), + MyImportPartFilter, Q_NULLPTR, + ((aRatio > 1) ? QFileDialog::DontUseNativeDialog : QFileDialog::Options())); + if (!aFile.isNull()) { + ModuleBase_OperationFeature* anImportPartOp = dynamic_cast( + module()->createOperation(ExchangePlugin_ImportPart::ID())); + if (operationMgr()->startOperation(anImportPartOp)) { + // initialize the filename to be imported + FeaturePtr aFeature = anImportPartOp->feature(); + aFeature->string(ExchangePlugin_ImportPart::FILE_PATH_ID())->setValue(aFile.toStdString()); + ModuleBase_Tools::flushUpdated(aFeature); + operationMgr()->commitOperation(); + } + } +} + +//****************************************************** +void XGUI_Workshop::onExportPart() +{ + if (abortAllOperations()) { + ModuleBase_OperationFeature* anExportPartOp = dynamic_cast( + module()->createOperation(ExchangePlugin_ExportPart::ID())); + operationMgr()->startOperation(anExportPartOp); + } +} + //****************************************************** ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule) { diff --git a/src/XGUI/XGUI_Workshop.h b/src/XGUI/XGUI_Workshop.h index 982758244..1bf77ba3f 100644 --- a/src/XGUI/XGUI_Workshop.h +++ b/src/XGUI/XGUI_Workshop.h @@ -397,6 +397,12 @@ signals: /// Create a new document void onNew(); + /// Import part structure from a file + void onImportPart(); + + /// Export features to a file + void onExportPart(); + #ifndef HAVE_SALOME /// Exit application void onExit();