From 218a67d92d01bf69a4ae39427fff0bab775ba67e Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 7 Nov 2024 11:37:54 +0000 Subject: [PATCH] Added collection of conversion outcomes during send Added progress display in UI (with ability to cancel) --- .../Interface/Browser/Bridge/Send/Send.cpp | 6 +- .../Record/Collection/ProjectCollection.cpp | 11 ++- .../Record/Collection/ProjectCollection.h | 3 +- SpeckleLib/RINT/Speckle.grc | 1 + .../Speckle/Interface/Component/Progress.cpp | 98 +++++++++++++++++++ .../Speckle/Interface/Component/Progress.h | 80 +++++++++++++++ SpeckleLib/Speckle/Record/Element/Element.cpp | 17 ++++ SpeckleLib/Speckle/Record/Element/Element.h | 5 + .../Speckle/Record/Element/ModelElement.cpp | 3 +- .../Collection/ConversionReporter.cpp | 45 +++++++++ .../Serialise/Collection/ConversionReporter.h | 77 +++++++++++++++ .../Serialise/Collection/FinishCollector.h | 2 +- SpeckleLib/Speckle/SpeckleResource.h | 1 + .../SpeckleLib.xcodeproj/project.pbxproj | 24 +++++ 14 files changed, 365 insertions(+), 8 deletions(-) create mode 100755 SpeckleLib/Speckle/Interface/Component/Progress.cpp create mode 100755 SpeckleLib/Speckle/Interface/Component/Progress.h create mode 100644 SpeckleLib/Speckle/Serialise/Collection/ConversionReporter.cpp create mode 100644 SpeckleLib/Speckle/Serialise/Collection/ConversionReporter.h diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 59813f7..9d6d407 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -83,12 +83,16 @@ void Send::run(const String& modelCardID) const { if (auto senderCard = dynamic_cast(modelCard.get())) { selected = senderCard->getFilter().getElementIDs(); } - //Build a collection from the selected elements auto collection = std::make_unique(project); for (const auto& link : selected) { if (auto element = elementDatabase->getElement(link); element) collection->addElement(*element); + else { + //Report these elements as failures for the report + collection->logRecord(link, ConversionReporter::Outcome::failure, false); + collection->incrementSkippedRecords(); + } } //Send the collected information auto result = std::make_unique(*modelCard, *account, SendObject{std::move(collection)}); diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp index 4389498..32049b7 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp @@ -12,6 +12,8 @@ #include "Speckle/Record/Attribute/Finish.h" #include "Speckle/Record/Element/Element.h" +#include + #ifdef ARCHICAD #include #include @@ -103,7 +105,10 @@ bool ProjectCollection::addElement(const speckle::record::element::Element& elem RecordCollection* collection = this; for (const auto& childName : collectionNames) collection = collection->getChild(childName); - return collection->addIndex(BIMIndex{element.getBIMID(), element.getTableID()}); + if (!collection->addIndex(BIMIndex{element.getBIMID(), element.getTableID()})) + return false; + incrementProjectedRecords(); + return true; } //ProjectCollection::addElement @@ -123,7 +128,6 @@ bool ProjectCollection::addFinishProxy(const speckle::database::BIMIndex& materi } //ProjectCollection::addFinishProxy -#ifdef ARCHICAD /*-------------------------------------------------------------------- Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method) @@ -138,7 +142,6 @@ bool ProjectCollection::addFinishProxy(const Finish& finish, const speckle::data iter = m_finishes->insert({finish.getBIMID(), finish}).first; return addFinishProxy(speckle::database::BIMIndex{finish.getBIMID()}, objectID); } //ProjectCollection::addFinishProxy -#endif /*-------------------------------------------------------------------- @@ -153,7 +156,7 @@ bool ProjectCollection::fillInventory(active::serialise::Inventory& inventory) c base::fillInventory(inventory); inventory.merge(Inventory{ { - { Identity{fieldID[finishProxyID]}, finishProxyID, 100, std::nullopt }, + { Identity{fieldID[finishProxyID]}, finishProxyID, std::numeric_limits::max(), std::nullopt }, }, }.withType(&typeid(ProjectCollection))); return true; diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h index 1bd6140..f271dd7 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h @@ -3,6 +3,7 @@ #include "Connector/Record/Collection/RecordCollection.h" #include "Speckle/Serialise/Collection/FinishCollector.h" +#include "Speckle/Serialise/Collection/ConversionReporter.h" #include @@ -25,7 +26,7 @@ namespace connector::record { - Other attributes, e.g. materials Add all this supplementary data to the root container as required */ - class ProjectCollection : public RecordCollection, public speckle::serialise::FinishCollector { + class ProjectCollection : public RecordCollection, public speckle::serialise::FinishCollector, public speckle::serialise::ConversionReporter { public: // MARK: - Types diff --git a/SpeckleLib/RINT/Speckle.grc b/SpeckleLib/RINT/Speckle.grc index 43c993f..aa8eab1 100644 --- a/SpeckleLib/RINT/Speckle.grc +++ b/SpeckleLib/RINT/Speckle.grc @@ -1,4 +1,5 @@ 'STR#' 32700 "Speckle Title strings" { /* [ 1] */ "Untitled" /* [ 2] */ "Unknown" +/* [ 3] */ "Converting elements" } diff --git a/SpeckleLib/Speckle/Interface/Component/Progress.cpp b/SpeckleLib/Speckle/Interface/Component/Progress.cpp new file mode 100755 index 0000000..d3d6326 --- /dev/null +++ b/SpeckleLib/Speckle/Interface/Component/Progress.cpp @@ -0,0 +1,98 @@ +#include "Speckle/Interface/Component/Progress.h" + +#ifdef ARCHICAD +#include "ACAPI_Interface.h" +#endif + +using namespace speckle::interfac; +using namespace speckle::utility; + +namespace { + + ///The progress class instance + Progress::Shared m_instance; + ///Mutex controlling management of the progress instance + std::mutex m_mutex; + +} + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +Progress::~Progress() { +#ifdef ARCHICAD + ACAPI_ProcessWindow_CloseProcessWindow(); +#endif +} //Progress::~Progress + + +/*-------------------------------------------------------------------- + Get a progress component instance + + title: The process title, i.e. for the overall operation. Ignored if an instance is already in operation + stages: The number of stages for completing the overall operation. Ignored if an instance is already in operation + + return: The progress instance - can be an active progress component if it has already been started (nullptr on failure) + --------------------------------------------------------------------*/ +Progress::Shared Progress::getInstance(const String& title, size_t stages) { + const std::lock_guard lock(m_mutex); + if (m_instance) + return m_instance; +#ifdef ARCHICAD + GS::UniString gsTitle{title}; + auto phases = static_cast(stages); + if (ACAPI_ProcessWindow_InitProcessWindow(&gsTitle, &phases) != NoError) + return nullptr; +#endif + m_instance = Progress::Shared{new Progress}; + return m_instance; +} //Progress::getInstance + + +/*-------------------------------------------------------------------- + Addition with assignment + + toAdd: The number of steps to add to the progress of the current stage + --------------------------------------------------------------------*/ +void Progress::operator+= (size_t toAdd) { +#ifdef ARCHICAD + auto incVal = static_cast(toAdd); + ACAPI_ProcessWindow_IncProcessValue(&incVal); +#endif +} //Progress::operator+= + + +/*-------------------------------------------------------------------- + Increment operator (increment the the progress of the current stage) + --------------------------------------------------------------------*/ +void Progress::operator++ () { + operator+=(1); +} //Progress::operator++ + + +/*-------------------------------------------------------------------- + Start the next stage + + title: The stage title + stepCount: The number of steps in this stage + showPercentage: True to estimate/display the process completion percentage + --------------------------------------------------------------------*/ +void Progress::startStage(const String& title, size_t stepCount, bool showPercentage) { +#ifdef ARCHICAD + GS::UniString gsTitle{title}; + auto maxVal = static_cast(stepCount); + ACAPI_ProcessWindow_SetNextProcessPhase(&gsTitle, &maxVal, &showPercentage); +#endif +} //Progress::startStage + + +/*-------------------------------------------------------------------- + Determine if the process has been cancelled, e.g. the user cancelling + + return: True if the process has been cancelled + --------------------------------------------------------------------*/ +bool Progress::isCancelled() { +#ifdef ARCHICAD + return (ACAPI_ProcessWindow_IsProcessCanceled() != NoError); +#endif +} //Progress::isCancelled diff --git a/SpeckleLib/Speckle/Interface/Component/Progress.h b/SpeckleLib/Speckle/Interface/Component/Progress.h new file mode 100755 index 0000000..3ce997b --- /dev/null +++ b/SpeckleLib/Speckle/Interface/Component/Progress.h @@ -0,0 +1,80 @@ +#ifndef SPECKLE_INTERFACE_PROGRESS +#define SPECKLE_INTERFACE_PROGRESS + +#include "Speckle/Utility/String.h" + +#include + +namespace speckle::interfac { + + /*! + Interface component to provide progress feedback during some long process to the user, e.g. a progress meter + + The structure of this component is intended for a host-wide singleton, i.e. a modal process that locks out other processes, rather than + simply (say) a progress bar as a component in a dialog/palette. This reflects the behaviour of Archicad but may be adapted to other + hosts + */ + class Progress { + public: + + // MARK: - Types + + ///Shared pointer + using Shared = std::shared_ptr; + + // MARK: - Constructors + + Progress(const Progress&) = delete; + /*! + Destructor + */ + ~Progress(); + + /*! + Get a progress component instance + @param title The process title, i.e. for the overall operation. Ignored if an instance is already in operation + @param stages The number of stages for completing the overall operation. Ignored if an instance is already in operation + @return The progress instance - can be an active progress component if it has already been started (nullptr on failure) + */ + static Shared getInstance(const utility::String& title = {}, size_t stages = 1); + + // MARK: - Operators + + /*! + Addition with assignment + @param toAdd The number of steps to add to the progress of the current stage + */ + void operator+= (size_t toAdd); + /*! + Increment operator (increment the the progress of the current stage) + */ + void operator++ (); + + // MARK: - Functions (const) + + /*! + Determine if the process has been cancelled, e.g. the user cancelling + @return True if the process has been cancelled + */ + bool isCancelled(); + + // MARK: - Functions (mutating) + + /*! + Start the next stage + @param title The stage title + @param stepCount The number of steps in this stage + @param showPercentage True to estimate/display the process completion percentage + */ + void startStage(const utility::String& title, size_t stepCount, bool showPercentage = true); + + private: + /*! + Default constructor + */ + Progress() {} + }; + +} + +#endif //SPECKLE_INTERFACE_PROGRESS diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index 37dfb91..5a42037 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -1,10 +1,12 @@ #include "Speckle/Record/Element/Element.h" +#include "Active/Serialise/Management/Management.h" #include "Speckle/Database/BIMElementDatabase.h" #include "Speckle/Environment/Addon.h" #include "Speckle/Environment/Project.h" #include "Speckle/Record/Element/Memo.h" #include "Speckle/Record/Element/Setting/TypeSetting.h" +#include "Speckle/Serialise/Collection/ConversionReporter.h" #include "Speckle/SpeckleResource.h" #include "Active/Serialise/CargoHold.h" @@ -13,6 +15,7 @@ using namespace speckle::database; using namespace speckle::environment; using namespace speckle::record::attribute; using namespace speckle::record::element; +using namespace speckle::serialise; using namespace speckle::utility; #include @@ -252,6 +255,20 @@ void Element::setDefault() { } //Element::setDefault +/*-------------------------------------------------------------------- + Use a manager in (de)serialisation processes + + management: The management to use + --------------------------------------------------------------------*/ +void Element::useManagement(Management* management) const { + if (management != nullptr) { + //If a conversion report is collected, add this record to the report (also updates progress display in the UI) + if (auto reporter = management->get(); reporter != nullptr) + reporter->logRecord(getBIMID()); + } +} //Element::useManagement + + /*-------------------------------------------------------------------- Load the element memo structure (elements must override according to requirements) diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index 6d8be67..073019f 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -117,6 +117,11 @@ namespace speckle::record::element { Set to the default package content */ void setDefault() override; + /*! + Use a manager in (de)serialisation processes + @param management The management to use + */ + void useManagement(active::serialise::Management* management) const override; protected: /*! diff --git a/SpeckleLib/Speckle/Record/Element/ModelElement.cpp b/SpeckleLib/Speckle/Record/Element/ModelElement.cpp index d191d9b..d190f35 100644 --- a/SpeckleLib/Speckle/Record/Element/ModelElement.cpp +++ b/SpeckleLib/Speckle/Record/Element/ModelElement.cpp @@ -428,7 +428,8 @@ Cargo::Unique ModelElement::getCargo(const Inventory::Item& item) const { return Cargo::Unique{new CargoHold, MaterialQuantityList>{quants}}; return nullptr; case propertyID: - return std::make_unique(*this); + return nullptr; + //return std::make_unique(*this); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleLib/Speckle/Serialise/Collection/ConversionReporter.cpp b/SpeckleLib/Speckle/Serialise/Collection/ConversionReporter.cpp new file mode 100644 index 0000000..b49a2ae --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Collection/ConversionReporter.cpp @@ -0,0 +1,45 @@ +#include "Speckle/Serialise/Collection/ConversionReporter.h" + +#include "Speckle/Environment/Addon.h" +#include "Speckle/Interface/Component/Progress.h" +#include "Speckle/SpeckleResource.h" + +using namespace speckle::database; +using namespace speckle::environment; +using namespace speckle::interfac; +using namespace speckle::serialise; + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +ConversionReporter::~ConversionReporter() {} + + +/*-------------------------------------------------------------------- + Log the conversion/serialisation of a record + + recordID: The ID of the serialised record + outcome: The record serialisation outcome + withUIFeedback: True if the UI progress feedback should be updated + + return: True if the serialisation should continue + --------------------------------------------------------------------*/ +bool ConversionReporter::logRecord(const BIMRecordID& recordID, Outcome outcome, bool withUIFeedback) { + //Initialise the progress UI component as required + if (withUIFeedback && !m_progress) { + if (m_progress = Progress::getInstance(addon()->getLocalString(titleStringLib, conversionProgressID)); m_progress) { + m_progress->startStage(addon()->getLocalString(titleStringLib, conversionProgressID), m_projectedRecordCount); + //If any records have already failed, mark them as complete in the UI progress display + if (m_skippedRecordCount > 0) + *m_progress += m_skippedRecordCount; + } + } + //Log the conversion outcome for the record + m_log[recordID] = outcome; + //Update the progress UI component + if (withUIFeedback && m_progress) { + ++(*m_progress); + return !m_progress->isCancelled(); + } + return true; +} //ConversionReporter::logRecord diff --git a/SpeckleLib/Speckle/Serialise/Collection/ConversionReporter.h b/SpeckleLib/Speckle/Serialise/Collection/ConversionReporter.h new file mode 100644 index 0000000..0cef9d1 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Collection/ConversionReporter.h @@ -0,0 +1,77 @@ +#ifndef SPECKLE_SERIALISE_CONVERSION_REPORTER +#define SPECKLE_SERIALISE_CONVERSION_REPORTER + +#include "Active/Serialise/Management/Manager.h" +#include "Speckle/Database/Identity/BIMRecordID.h" + +namespace speckle::interfac { + class Progress; +} + +namespace speckle::serialise { + + /*! + Manager for reporting on the progress of a send conversion/serialisation process + */ + class ConversionReporter : public virtual active::serialise::Manager { + public: + + ///Record conversion status + enum class Outcome { + success, + failure, + }; + ///Reporter log pairing a record ID with the outcome of its conversion + using Log = std::unordered_map; + + // MARK: Constructors + + /*! + Destructor + */ + virtual ~ConversionReporter(); + + // MARK: - Functions (const) + + /*! + Get the conversion log + @return The conversion log + */ + const Log& getLog() const { return m_log; } + + // MARK: - Functions (mutating) + + /*! + Increment the number of projected records to be logged + */ + void incrementProjectedRecords() { ++m_projectedRecordCount; } + /*! + Increment the number of skipped records (and add to the projected record count) + */ + void incrementSkippedRecords() { + ++m_projectedRecordCount; + incrementProjectedRecords(); + } + /*! + Log the conversion/serialisation of a record + @param recordID The ID of the serialised record + @param outcome The record serialisation outcome + @param withUIFeedback True if the UI progress feedback should be updated + @return True if the serialisation should continue + */ + bool logRecord(const speckle::database::BIMRecordID& recordID, Outcome outcome = Outcome::success, bool withUIFeedback = true); + + private: + ///The reporter log + Log m_log; + ///The conversion progress UI display + std::shared_ptr m_progress; + ///Projected number of records to be logged (used to calculate UI progress components) + size_t m_projectedRecordCount = 0; + ///Number of records skipped (before processing starts - the UI progress feedback will reflect their completion) + size_t m_skippedRecordCount = 0; + }; + +} + +#endif //SPECKLE_SERIALISE_CONVERSION_REPORTER diff --git a/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h b/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h index 2b63dda..f689f1a 100644 --- a/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h +++ b/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h @@ -14,7 +14,7 @@ namespace speckle::serialise { Used as a serialisation manager to collect finishes from serialised objects */ - class FinishCollector : public active::serialise::Manager { + class FinishCollector : public virtual active::serialise::Manager { public: /*! Destructor diff --git a/SpeckleLib/Speckle/SpeckleResource.h b/SpeckleLib/Speckle/SpeckleResource.h index bc56020..fe63be4 100755 --- a/SpeckleLib/Speckle/SpeckleResource.h +++ b/SpeckleLib/Speckle/SpeckleResource.h @@ -15,6 +15,7 @@ enum SpeckleStringResource { enum SpeckleTitleString { untitledProjectID = 1, unknownElementTypeID, + conversionProgressID, }; diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index b24116a..ed4c1e2 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -76,6 +76,10 @@ 2196F3042CB57E8000450DFC /* Storey.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F3022CB57E7F00450DFC /* Storey.h */; }; 2196F3052CB57E8000450DFC /* Storey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F3032CB57E7F00450DFC /* Storey.cpp */; }; 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; + 2199BB6D2CDBF09900A4BEEC /* ConversionReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2199BB6A2CDBF09900A4BEEC /* ConversionReporter.h */; }; + 2199BB6F2CDC2B2500A4BEEC /* ConversionReporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2199BB6E2CDC2B2500A4BEEC /* ConversionReporter.cpp */; }; + 2199BB732CDCB0D500A4BEEC /* Progress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2199BB702CDCB0D500A4BEEC /* Progress.cpp */; }; + 2199BB742CDCB0D500A4BEEC /* Progress.h in Headers */ = {isa = PBXBuildFile; fileRef = 2199BB712CDCB0D500A4BEEC /* Progress.h */; }; 21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FB9F2CB880690023F24E /* FinishCollector.h */; }; 21A0FBB52CBA5E380023F24E /* Str256.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB42CBA5E380023F24E /* Str256.h */; }; 21A0FBBC2CBBC04C0023F24E /* ArchicadRGB.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */; }; @@ -304,6 +308,10 @@ 2196F3032CB57E7F00450DFC /* Storey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storey.cpp; sourceTree = ""; }; 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; 2199BB5F2CDB761B00A4BEEC /* ElementStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementStorage.h; sourceTree = ""; }; + 2199BB6A2CDBF09900A4BEEC /* ConversionReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversionReporter.h; sourceTree = ""; }; + 2199BB6E2CDC2B2500A4BEEC /* ConversionReporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConversionReporter.cpp; sourceTree = ""; }; + 2199BB702CDCB0D500A4BEEC /* Progress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Progress.cpp; sourceTree = ""; }; + 2199BB712CDCB0D500A4BEEC /* Progress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Progress.h; sourceTree = ""; }; 21A0FB9F2CB880690023F24E /* FinishCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishCollector.h; sourceTree = ""; }; 21A0FBA92CB9324A0023F24E /* FinishProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = ""; }; 21A0FBB42CBA5E380023F24E /* Str256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Str256.h; sourceTree = ""; }; @@ -717,9 +725,20 @@ path = Element; sourceTree = ""; }; + 2199BB722CDCB0D500A4BEEC /* Component */ = { + isa = PBXGroup; + children = ( + 2199BB702CDCB0D500A4BEEC /* Progress.cpp */, + 2199BB712CDCB0D500A4BEEC /* Progress.h */, + ); + path = Component; + sourceTree = ""; + }; 21A0FBA02CB880690023F24E /* Collection */ = { isa = PBXGroup; children = ( + 2199BB6E2CDC2B2500A4BEEC /* ConversionReporter.cpp */, + 2199BB6A2CDBF09900A4BEEC /* ConversionReporter.h */, 21A0FB9F2CB880690023F24E /* FinishCollector.h */, 21A0FBA92CB9324A0023F24E /* FinishProxy.h */, ); @@ -921,6 +940,7 @@ isa = PBXGroup; children = ( 21F69F1A2C6A0FE2008B6A06 /* Browser */, + 2199BB722CDCB0D500A4BEEC /* Component */, ); path = Interface; sourceTree = ""; @@ -1034,6 +1054,7 @@ 21AE19AD2CC8F214004DBCFC /* SegmentedBeam.h in Headers */, 21384C1D2CD586D800D4602B /* Morph.h in Headers */, 21D0BDE72C943D3F0077E104 /* RecordID.h in Headers */, + 2199BB742CDCB0D500A4BEEC /* Progress.h in Headers */, 21D0BD212C86F0280077E104 /* AccountDatabase.h in Headers */, 21A0FBB52CBA5E380023F24E /* Str256.h in Headers */, 210CC86F2C7E879700610F58 /* ArgumentBase.h in Headers */, @@ -1083,6 +1104,7 @@ 2196F3042CB57E8000450DFC /* Storey.h in Headers */, 21384C042CD57CA500D4602B /* Wall.h in Headers */, 21AE196F2CC64D37004DBCFC /* Classified.h in Headers */, + 2199BB6D2CDBF09900A4BEEC /* ConversionReporter.h in Headers */, 21AE19522CC273F1004DBCFC /* Property.h in Headers */, 21A0FBF92CBDB9A70023F24E /* BIMMemory.h in Headers */, 21AE19AA2CC8F1F8004DBCFC /* BeamSegment.h in Headers */, @@ -1255,6 +1277,7 @@ 2196F2F82CB51ED400450DFC /* BIMAttributeDatabase.cpp in Sources */, 21D0BD4E2C8901A00077E104 /* ServerInfo.cpp in Sources */, 21AE19512CC273F1004DBCFC /* Property.cpp in Sources */, + 2199BB732CDCB0D500A4BEEC /* Progress.cpp in Sources */, 21384BED2CD3EBE200D4602B /* Material.cpp in Sources */, 21384C252CD59B4100D4602B /* MeshElem.cpp in Sources */, 21B67D0E2C7E0E8D00FD64FC /* ErrorReport.cpp in Sources */, @@ -1295,6 +1318,7 @@ 21F69F512C6CCC25008B6A06 /* BrowserBridge.cpp in Sources */, 21A0FC112CBEE5C30023F24E /* Part.cpp in Sources */, 21384C212CD5880400D4602B /* Shell.cpp in Sources */, + 2199BB6F2CDC2B2500A4BEEC /* ConversionReporter.cpp in Sources */, 21A890D12CC1B87C0087E732 /* GenericModelElement.cpp in Sources */, 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */, 215F08552C99DA8D00CD343B /* Project.cpp in Sources */,