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
This commit is contained in:
Submodule mods/silo updated: 914d97f9a0...27e112e7da
@@ -49,7 +49,9 @@
|
|||||||
#include "Control.h"
|
#include "Control.h"
|
||||||
#include "DockWindowManager.h"
|
#include "DockWindowManager.h"
|
||||||
#include "FileDialog.h"
|
#include "FileDialog.h"
|
||||||
|
#include "FileOrigin.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
#include "OriginManager.h"
|
||||||
#include "Selection.h"
|
#include "Selection.h"
|
||||||
#include "Dialogs/DlgObjectSelection.h"
|
#include "Dialogs/DlgObjectSelection.h"
|
||||||
#include "Dialogs/DlgProjectInformationImp.h"
|
#include "Dialogs/DlgProjectInformationImp.h"
|
||||||
@@ -95,81 +97,25 @@ void StdCmdOpen::activated(int iMsg)
|
|||||||
{
|
{
|
||||||
Q_UNUSED(iMsg);
|
Q_UNUSED(iMsg);
|
||||||
|
|
||||||
// fill the list of registered endings
|
// Delegate to current origin
|
||||||
QString formatList;
|
FileOrigin* origin = OriginManager::instance()->currentOrigin();
|
||||||
const char* supported = QT_TR_NOOP("Supported formats");
|
if (!origin) {
|
||||||
const char* allFiles = QT_TR_NOOP("All files (*.*)");
|
|
||||||
formatList = QObject::tr(supported);
|
|
||||||
formatList += QLatin1String(" (");
|
|
||||||
|
|
||||||
std::vector<std::string> 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<std::string, std::string> FilterList = App::GetApplication().getImportFilters();
|
|
||||||
std::map<std::string, std::string>::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()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the files with the associated modules
|
// Check connection for origins that require authentication
|
||||||
SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter);
|
if (origin->requiresAuthentication() &&
|
||||||
if (dict.isEmpty()) {
|
origin->connectionState() != ConnectionState::Connected) {
|
||||||
QMessageBox::critical(
|
QMessageBox::warning(
|
||||||
getMainWindow(),
|
getMainWindow(),
|
||||||
qApp->translate("StdCmdOpen", "Cannot Open File"),
|
qApp->translate("StdCmdOpen", "Not Connected"),
|
||||||
qApp->translate("StdCmdOpen", "Loading the file %1 is not supported").arg(fileList.front())
|
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)
|
origin->openDocumentInteractive();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
@@ -715,10 +661,27 @@ StdCmdNew::StdCmdNew()
|
|||||||
void StdCmdNew::activated(int iMsg)
|
void StdCmdNew::activated(int iMsg)
|
||||||
{
|
{
|
||||||
Q_UNUSED(iMsg);
|
Q_UNUSED(iMsg);
|
||||||
QString cmd;
|
|
||||||
cmd = QStringLiteral("App.newDocument()");
|
// Delegate to current origin
|
||||||
runCommand(Command::Doc, cmd.toUtf8());
|
FileOrigin* origin = OriginManager::instance()->currentOrigin();
|
||||||
doCommand(Command::Gui, "Gui.activeDocument().activeView().viewDefaultOrientation()");
|
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<View3DInventor*>(view);
|
||||||
|
view3d->getViewer()->viewDefaultOrientation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ParameterGrp::handle hViewGrp = App::GetApplication().GetParameterGroupByPath(
|
ParameterGrp::handle hViewGrp = App::GetApplication().GetParameterGroupByPath(
|
||||||
"User parameter:BaseApp/Preferences/View"
|
"User parameter:BaseApp/Preferences/View"
|
||||||
@@ -749,12 +712,33 @@ StdCmdSave::StdCmdSave()
|
|||||||
void StdCmdSave::activated(int iMsg)
|
void StdCmdSave::activated(int iMsg)
|
||||||
{
|
{
|
||||||
Q_UNUSED(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()
|
bool StdCmdSave::isActive()
|
||||||
{
|
{
|
||||||
return getGuiApplication()->sendHasMsgToActiveView("Save");
|
return App::GetApplication().getActiveDocument() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
@@ -778,12 +762,24 @@ StdCmdSaveAs::StdCmdSaveAs()
|
|||||||
void StdCmdSaveAs::activated(int iMsg)
|
void StdCmdSaveAs::activated(int iMsg)
|
||||||
{
|
{
|
||||||
Q_UNUSED(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()
|
bool StdCmdSaveAs::isActive()
|
||||||
{
|
{
|
||||||
return getGuiApplication()->sendHasMsgToActiveView("SaveAs");
|
return App::GetApplication().getActiveDocument() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|||||||
@@ -22,15 +22,23 @@
|
|||||||
|
|
||||||
#include "PreCompiled.h"
|
#include "PreCompiled.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include <App/Application.h>
|
#include <App/Application.h>
|
||||||
#include <App/Document.h>
|
#include <App/Document.h>
|
||||||
#include <App/DocumentObject.h>
|
#include <App/DocumentObject.h>
|
||||||
#include <App/PropertyStandard.h>
|
#include <App/PropertyStandard.h>
|
||||||
|
|
||||||
#include "FileOrigin.h"
|
#include "FileOrigin.h"
|
||||||
|
#include "Application.h"
|
||||||
#include "BitmapFactory.h"
|
#include "BitmapFactory.h"
|
||||||
#include "Document.h"
|
#include "Document.h"
|
||||||
#include "Application.h"
|
#include "FileDialog.h"
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include "SelectModule.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Gui {
|
namespace Gui {
|
||||||
@@ -99,6 +107,86 @@ App::Document* LocalFileOrigin::openDocument(const std::string& identity)
|
|||||||
return App::GetApplication().openDocument(identity.c_str());
|
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<std::string> 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<std::string, std::string> 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)
|
bool LocalFileOrigin::saveDocument(App::Document* doc)
|
||||||
{
|
{
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
@@ -125,4 +213,20 @@ bool LocalFileOrigin::saveDocumentAs(App::Document* doc, const std::string& newI
|
|||||||
return doc->saveAs(newIdentity.c_str());
|
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
|
} // namespace Gui
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ public:
|
|||||||
virtual App::Document* newDocument(const std::string& name = "") = 0;
|
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
|
* Local: Opens file at path
|
||||||
* PLM: Opens document by UUID (downloads if needed)
|
* PLM: Opens document by UUID (downloads if needed)
|
||||||
* @param identity Document identity (path or UUID)
|
* @param identity Document identity (path or UUID)
|
||||||
@@ -176,9 +176,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual App::Document* openDocument(const std::string& identity) = 0;
|
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.
|
* Save the document.
|
||||||
* Local: Saves to disk
|
* Local: Saves to disk (if path known)
|
||||||
* PLM: Saves to disk and syncs with external system
|
* PLM: Saves to disk and syncs with external system
|
||||||
* @param doc The document to save
|
* @param doc The document to save
|
||||||
* @return true if save succeeded
|
* @return true if save succeeded
|
||||||
@@ -186,14 +194,21 @@ public:
|
|||||||
virtual bool saveDocument(App::Document* doc) = 0;
|
virtual bool saveDocument(App::Document* doc) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save document with new identity.
|
* Save document with new identity (non-interactive).
|
||||||
* Local: File picker for new path
|
|
||||||
* PLM: Migration or copy workflow
|
|
||||||
* @param doc The document to save
|
* @param doc The document to save
|
||||||
* @param newIdentity New identity (path or part number)
|
* @param newIdentity New identity (path or part number)
|
||||||
* @return true if save succeeded
|
* @return true if save succeeded
|
||||||
*/
|
*/
|
||||||
virtual bool saveDocumentAs(App::Document* doc, const std::string& newIdentity) = 0;
|
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)
|
///@name Extended Operations (PLM-specific, default to no-op)
|
||||||
@@ -250,8 +265,10 @@ public:
|
|||||||
// Document operations
|
// Document operations
|
||||||
App::Document* newDocument(const std::string& name = "") override;
|
App::Document* newDocument(const std::string& name = "") override;
|
||||||
App::Document* openDocument(const std::string& identity) override;
|
App::Document* openDocument(const std::string& identity) override;
|
||||||
|
App::Document* openDocumentInteractive() override;
|
||||||
bool saveDocument(App::Document* doc) override;
|
bool saveDocument(App::Document* doc) override;
|
||||||
bool saveDocumentAs(App::Document* doc, const std::string& newIdentity) override;
|
bool saveDocumentAs(App::Document* doc, const std::string& newIdentity) override;
|
||||||
|
bool saveDocumentAsInteractive(App::Document* doc) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Gui
|
} // namespace Gui
|
||||||
|
|||||||
Reference in New Issue
Block a user