From 38358e431d2e68a1f4f4f1d4a40d7bfbb66e1416 Mon Sep 17 00:00:00 2001 From: forbes-0023 Date: Thu, 5 Feb 2026 14:02:26 -0600 Subject: [PATCH] feat(gui): implement issues #10 and #12 - LocalFileOrigin and Std_* delegation Issue #10: Local filesystem origin implementation - Add openDocumentInteractive() method to FileOrigin interface for UI-based file opening (shows file dialog) - Add saveDocumentAsInteractive() method for UI-based save as - Implement LocalFileOrigin::openDocumentInteractive() with full file dialog support, filter list building, and module handler integration - Implement LocalFileOrigin::saveDocumentAsInteractive() delegating to Gui::Document::saveAs() Issue #12: Modify Std_* commands to delegate to current origin - StdCmdNew::activated() now delegates to origin->newDocument() and sets up view orientation for the new document - StdCmdOpen::activated() delegates to origin->openDocumentInteractive() with connection state checking for authenticated origins - StdCmdSave::activated() uses document's owning origin (via findOwningOrigin) for save, falling back to saveDocumentAsInteractive if no filename - StdCmdSaveAs::activated() delegates to origin->saveDocumentAsInteractive() - Updated isActive() methods to check for active document The Std_* commands now work seamlessly with both LocalFileOrigin and SiloOrigin. When Local origin is selected, standard file dialogs appear. When Silo origin is selected, Silo's search/creation dialogs appear. Import and Export commands are left unchanged as they operate on document content rather than document lifecycle. Closes #10, Closes #12 --- mods/silo | 2 +- src/Gui/CommandDoc.cpp | 148 ++++++++++++++++++++--------------------- src/Gui/FileOrigin.cpp | 106 ++++++++++++++++++++++++++++- src/Gui/FileOrigin.h | 27 ++++++-- 4 files changed, 200 insertions(+), 83 deletions(-) diff --git a/mods/silo b/mods/silo index 914d97f9a0..27e112e7da 160000 --- a/mods/silo +++ b/mods/silo @@ -1 +1 @@ -Subproject commit 914d97f9a0e392906f8a805ef376ee2b2e562a70 +Subproject commit 27e112e7da5eafe38d02b255e38013879c231a02 diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 421a079c14..21789ceb70 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -49,7 +49,9 @@ #include "Control.h" #include "DockWindowManager.h" #include "FileDialog.h" +#include "FileOrigin.h" #include "MainWindow.h" +#include "OriginManager.h" #include "Selection.h" #include "Dialogs/DlgObjectSelection.h" #include "Dialogs/DlgProjectInformationImp.h" @@ -95,81 +97,25 @@ void StdCmdOpen::activated(int iMsg) { Q_UNUSED(iMsg); - // fill the list of registered endings - QString formatList; - const char* supported = QT_TR_NOOP("Supported formats"); - const char* allFiles = QT_TR_NOOP("All files (*.*)"); - formatList = QObject::tr(supported); - formatList += QLatin1String(" ("); - - std::vector filetypes = App::GetApplication().getImportTypes(); - // Make sure FCStd is the very first fileformat - auto it = std::ranges::find(filetypes, "FCStd"); - if (it != filetypes.end()) { - filetypes.erase(it); - filetypes.insert(filetypes.begin(), "FCStd"); - } - for (it = filetypes.begin(); it != filetypes.end(); ++it) { - formatList += QLatin1String(" *."); - formatList += QLatin1String(it->c_str()); - } - - formatList += QLatin1String(");;"); - - std::map FilterList = App::GetApplication().getImportFilters(); - std::map::iterator jt; - // Make sure the format name for FCStd is the very first in the list - for (jt = FilterList.begin(); jt != FilterList.end(); ++jt) { - if (jt->first.find("*.FCStd") != std::string::npos) { - formatList += QLatin1String(jt->first.c_str()); - formatList += QLatin1String(";;"); - FilterList.erase(jt); - break; - } - } - for (jt = FilterList.begin(); jt != FilterList.end(); ++jt) { - formatList += QLatin1String(jt->first.c_str()); - formatList += QLatin1String(";;"); - } - formatList += QObject::tr(allFiles); - - QString selectedFilter; - QStringList fileList = FileDialog::getOpenFileNames( - getMainWindow(), - QObject::tr("Open Document"), - QString(), - formatList, - &selectedFilter - ); - if (fileList.isEmpty()) { + // Delegate to current origin + FileOrigin* origin = OriginManager::instance()->currentOrigin(); + if (!origin) { return; } - // load the files with the associated modules - SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter); - if (dict.isEmpty()) { - QMessageBox::critical( + // Check connection for origins that require authentication + if (origin->requiresAuthentication() && + origin->connectionState() != ConnectionState::Connected) { + QMessageBox::warning( getMainWindow(), - qApp->translate("StdCmdOpen", "Cannot Open File"), - qApp->translate("StdCmdOpen", "Loading the file %1 is not supported").arg(fileList.front()) + qApp->translate("StdCmdOpen", "Not Connected"), + qApp->translate("StdCmdOpen", "Please connect to %1 before opening files.") + .arg(QString::fromStdString(origin->name())) ); + return; } - else { - for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) { - // Set flag indicating that this load/restore has been initiated by the user (not by a macro) - getGuiApplication()->setStatus(Gui::Application::UserInitiatedOpenDocument, true); - - getGuiApplication()->open(it.key().toUtf8(), it.value().toLatin1()); - - getGuiApplication()->setStatus(Gui::Application::UserInitiatedOpenDocument, false); - - App::Document* doc = App::GetApplication().getActiveDocument(); - - getGuiApplication()->checkPartialRestore(doc); - getGuiApplication()->checkRestoreError(doc); - } - } + origin->openDocumentInteractive(); } //=========================================================================== @@ -715,10 +661,27 @@ StdCmdNew::StdCmdNew() void StdCmdNew::activated(int iMsg) { Q_UNUSED(iMsg); - QString cmd; - cmd = QStringLiteral("App.newDocument()"); - runCommand(Command::Doc, cmd.toUtf8()); - doCommand(Command::Gui, "Gui.activeDocument().activeView().viewDefaultOrientation()"); + + // Delegate to current origin + FileOrigin* origin = OriginManager::instance()->currentOrigin(); + if (!origin) { + return; + } + + App::Document* doc = origin->newDocument(); + if (!doc) { + return; + } + + // Set default view orientation for the new document + Gui::Document* guiDoc = Application::Instance->getDocument(doc); + if (guiDoc) { + auto views = guiDoc->getMDIViewsOfType(View3DInventor::getClassTypeId()); + for (auto* view : views) { + auto view3d = static_cast(view); + view3d->getViewer()->viewDefaultOrientation(); + } + } ParameterGrp::handle hViewGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/View" @@ -749,12 +712,33 @@ StdCmdSave::StdCmdSave() void StdCmdSave::activated(int iMsg) { Q_UNUSED(iMsg); - doCommand(Command::Gui, "Gui.SendMsgToActiveView(\"Save\")"); + + App::Document* doc = App::GetApplication().getActiveDocument(); + if (!doc) { + return; + } + + // Use document's origin for save, not current origin + FileOrigin* origin = OriginManager::instance()->findOwningOrigin(doc); + if (!origin) { + // Document has no origin yet - use current origin for first save + origin = OriginManager::instance()->currentOrigin(); + } + + if (!origin) { + return; + } + + // Try to save the document + if (!origin->saveDocument(doc)) { + // If save failed (e.g., no filename), try SaveAs + origin->saveDocumentAsInteractive(doc); + } } bool StdCmdSave::isActive() { - return getGuiApplication()->sendHasMsgToActiveView("Save"); + return App::GetApplication().getActiveDocument() != nullptr; } //=========================================================================== @@ -778,12 +762,24 @@ StdCmdSaveAs::StdCmdSaveAs() void StdCmdSaveAs::activated(int iMsg) { Q_UNUSED(iMsg); - doCommand(Command::Gui, "Gui.SendMsgToActiveView(\"SaveAs\")"); + + App::Document* doc = App::GetApplication().getActiveDocument(); + if (!doc) { + return; + } + + // SaveAs uses current origin (allows saving to different origin) + FileOrigin* origin = OriginManager::instance()->currentOrigin(); + if (!origin) { + return; + } + + origin->saveDocumentAsInteractive(doc); } bool StdCmdSaveAs::isActive() { - return getGuiApplication()->sendHasMsgToActiveView("SaveAs"); + return App::GetApplication().getActiveDocument() != nullptr; } //=========================================================================== diff --git a/src/Gui/FileOrigin.cpp b/src/Gui/FileOrigin.cpp index 0ed5c9ba81..818e859f51 100644 --- a/src/Gui/FileOrigin.cpp +++ b/src/Gui/FileOrigin.cpp @@ -22,15 +22,23 @@ #include "PreCompiled.h" +#include + +#include +#include + #include #include #include #include #include "FileOrigin.h" +#include "Application.h" #include "BitmapFactory.h" #include "Document.h" -#include "Application.h" +#include "FileDialog.h" +#include "MainWindow.h" +#include "SelectModule.h" namespace Gui { @@ -99,6 +107,86 @@ App::Document* LocalFileOrigin::openDocument(const std::string& identity) return App::GetApplication().openDocument(identity.c_str()); } +App::Document* LocalFileOrigin::openDocumentInteractive() +{ + // Build file filter list for Open dialog + QString formatList; + const char* supported = QT_TR_NOOP("Supported formats"); + const char* allFiles = QT_TR_NOOP("All files (*.*)"); + formatList = QObject::tr(supported); + formatList += QLatin1String(" ("); + + std::vector filetypes = App::GetApplication().getImportTypes(); + // Make sure FCStd is the very first fileformat + auto it = std::find(filetypes.begin(), filetypes.end(), "FCStd"); + if (it != filetypes.end()) { + filetypes.erase(it); + filetypes.insert(filetypes.begin(), "FCStd"); + } + for (it = filetypes.begin(); it != filetypes.end(); ++it) { + formatList += QLatin1String(" *."); + formatList += QLatin1String(it->c_str()); + } + + formatList += QLatin1String(");;"); + + std::map FilterList = App::GetApplication().getImportFilters(); + // Make sure the format name for FCStd is the very first in the list + for (auto jt = FilterList.begin(); jt != FilterList.end(); ++jt) { + if (jt->first.find("*.FCStd") != std::string::npos) { + formatList += QLatin1String(jt->first.c_str()); + formatList += QLatin1String(";;"); + FilterList.erase(jt); + break; + } + } + for (const auto& filter : FilterList) { + formatList += QLatin1String(filter.first.c_str()); + formatList += QLatin1String(";;"); + } + formatList += QObject::tr(allFiles); + + QString selectedFilter; + QStringList fileList = FileDialog::getOpenFileNames( + getMainWindow(), + QObject::tr("Open Document"), + QString(), + formatList, + &selectedFilter + ); + if (fileList.isEmpty()) { + return nullptr; + } + + // Load the files with the associated modules + SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter); + if (dict.isEmpty()) { + QMessageBox::critical( + getMainWindow(), + qApp->translate("StdCmdOpen", "Cannot Open File"), + qApp->translate("StdCmdOpen", "Loading the file %1 is not supported").arg(fileList.front()) + ); + return nullptr; + } + + App::Document* lastDoc = nullptr; + for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) { + // Set flag indicating that this load/restore has been initiated by the user + Application::Instance->setStatus(Gui::Application::UserInitiatedOpenDocument, true); + + Application::Instance->open(it.key().toUtf8(), it.value().toLatin1()); + + Application::Instance->setStatus(Gui::Application::UserInitiatedOpenDocument, false); + + lastDoc = App::GetApplication().getActiveDocument(); + + Application::Instance->checkPartialRestore(lastDoc); + Application::Instance->checkRestoreError(lastDoc); + } + + return lastDoc; +} + bool LocalFileOrigin::saveDocument(App::Document* doc) { if (!doc) { @@ -125,4 +213,20 @@ bool LocalFileOrigin::saveDocumentAs(App::Document* doc, const std::string& newI return doc->saveAs(newIdentity.c_str()); } +bool LocalFileOrigin::saveDocumentAsInteractive(App::Document* doc) +{ + if (!doc) { + return false; + } + + // Get Gui document for save dialog + Gui::Document* guiDoc = Application::Instance->getDocument(doc); + if (!guiDoc) { + return false; + } + + // Use Gui::Document::saveAs() which handles the file dialog + return guiDoc->saveAs(); +} + } // namespace Gui diff --git a/src/Gui/FileOrigin.h b/src/Gui/FileOrigin.h index 26323e8d18..aee753797d 100644 --- a/src/Gui/FileOrigin.h +++ b/src/Gui/FileOrigin.h @@ -168,7 +168,7 @@ public: virtual App::Document* newDocument(const std::string& name = "") = 0; /** - * Open a document by identity. + * Open a document by identity (non-interactive). * Local: Opens file at path * PLM: Opens document by UUID (downloads if needed) * @param identity Document identity (path or UUID) @@ -176,9 +176,17 @@ public: */ virtual App::Document* openDocument(const std::string& identity) = 0; + /** + * Open a document interactively (shows dialog). + * Local: Shows file picker dialog + * PLM: Shows search/browse dialog + * @return The opened document or nullptr if cancelled/failed + */ + virtual App::Document* openDocumentInteractive() = 0; + /** * Save the document. - * Local: Saves to disk + * Local: Saves to disk (if path known) * PLM: Saves to disk and syncs with external system * @param doc The document to save * @return true if save succeeded @@ -186,14 +194,21 @@ public: virtual bool saveDocument(App::Document* doc) = 0; /** - * Save document with new identity. - * Local: File picker for new path - * PLM: Migration or copy workflow + * Save document with new identity (non-interactive). * @param doc The document to save * @param newIdentity New identity (path or part number) * @return true if save succeeded */ virtual bool saveDocumentAs(App::Document* doc, const std::string& newIdentity) = 0; + + /** + * Save document interactively (shows dialog). + * Local: Shows file picker for new path + * PLM: Shows migration or copy workflow dialog + * @param doc The document to save + * @return true if save succeeded + */ + virtual bool saveDocumentAsInteractive(App::Document* doc) = 0; //@} ///@name Extended Operations (PLM-specific, default to no-op) @@ -250,8 +265,10 @@ public: // Document operations App::Document* newDocument(const std::string& name = "") override; App::Document* openDocument(const std::string& identity) override; + App::Document* openDocumentInteractive() override; bool saveDocument(App::Document* doc) override; bool saveDocumentAs(App::Document* doc, const std::string& newIdentity) override; + bool saveDocumentAsInteractive(App::Document* doc) override; }; } // namespace Gui