Files
create/src/Gui/FileOrigin.h
forbes-0023 38358e431d 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
2026-02-05 14:02:26 -06:00

277 lines
10 KiB
C++

/***************************************************************************
* Copyright (c) 2025 Kindred Systems *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef GUI_FILEORIGIN_H
#define GUI_FILEORIGIN_H
#include <string>
#include <QIcon>
#include <FCGlobal.h>
#include <fastsignals/signal.h>
namespace App {
class Document;
}
namespace Gui {
/**
* @brief Classification of origin types
*/
enum class OriginType {
Local, ///< Local filesystem storage
PLM, ///< Product Lifecycle Management system (e.g., Silo)
Cloud, ///< Generic cloud storage
Custom ///< User-defined origin type
};
/**
* @brief Connection state for origins that require network access
*/
enum class ConnectionState {
Disconnected, ///< Not connected
Connecting, ///< Connection in progress
Connected, ///< Successfully connected
Error ///< Connection error occurred
};
/**
* @brief Abstract base class for document origin handlers
*
* FileOrigin provides an interface for different storage backends
* that can handle FreeCAD documents. Each origin defines workflows
* for creating, opening, saving, and managing documents.
*
* Key insight: Origins don't change where files are stored - all documents
* are always saved locally. Origins change the workflow and identity model:
* - Local: Document identity = file path, no external tracking
* - PLM: Document identity = database UUID, syncs with external system
*/
class GuiExport FileOrigin
{
public:
virtual ~FileOrigin() = default;
///@name Identity Methods
//@{
/** Unique identifier for this origin instance */
virtual std::string id() const = 0;
/** Display name for UI */
virtual std::string name() const = 0;
/** Short nickname for compact UI elements (e.g., toolbar) */
virtual std::string nickname() const = 0;
/** Icon for UI representation */
virtual QIcon icon() const = 0;
/** Origin type classification */
virtual OriginType type() const = 0;
//@}
///@name Workflow Characteristics
//@{
/** Whether this origin tracks documents externally (e.g., in a database) */
virtual bool tracksExternally() const = 0;
/** Whether this origin requires user authentication */
virtual bool requiresAuthentication() const = 0;
//@}
///@name Capability Queries
//@{
/** Whether this origin supports revision history */
virtual bool supportsRevisions() const { return false; }
/** Whether this origin supports Bill of Materials */
virtual bool supportsBOM() const { return false; }
/** Whether this origin supports part numbers */
virtual bool supportsPartNumbers() const { return false; }
/** Whether this origin supports assemblies natively */
virtual bool supportsAssemblies() const { return false; }
//@}
///@name Connection State
//@{
/** Get current connection state */
virtual ConnectionState connectionState() const { return ConnectionState::Connected; }
/** Attempt to connect/authenticate */
virtual bool connect() { return true; }
/** Disconnect from origin */
virtual void disconnect() {}
/** Signal emitted when connection state changes */
fastsignals::signal<void(ConnectionState)> signalConnectionStateChanged;
//@}
///@name Document Identity
//@{
/**
* Get document identity string (path for local, UUID for PLM)
* This is the immutable tracking key for the document.
* @param doc The App document to get identity for
* @return Identity string or empty if not owned by this origin
*/
virtual std::string documentIdentity(App::Document* doc) const = 0;
/**
* Get human-readable document identity (path for local, part number for PLM)
* This is for display purposes in the UI.
* @param doc The App document
* @return Display identity string or empty if not owned
*/
virtual std::string documentDisplayId(App::Document* doc) const = 0;
/**
* Check if this origin owns the given document.
* Ownership is determined by document properties, not file path.
* @param doc The document to check
* @return true if this origin owns the document
*/
virtual bool ownsDocument(App::Document* doc) const = 0;
//@}
///@name Property Synchronization
//@{
/**
* Sync document properties to the origin backend.
* For local origin this is a no-op. For PLM origins this pushes
* property changes to the database.
* @param doc The document to sync
* @return true if sync succeeded
*/
virtual bool syncProperties(App::Document* doc) { (void)doc; return true; }
//@}
///@name Core Document Operations
//@{
/**
* Create a new document managed by this origin.
* Local: Creates empty document
* PLM: Shows part creation form
* @param name Optional document name
* @return The created document or nullptr on failure
*/
virtual App::Document* newDocument(const std::string& name = "") = 0;
/**
* 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)
* @return The opened document or nullptr on failure
*/
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 (if path known)
* PLM: Saves to disk and syncs with external system
* @param doc The document to save
* @return true if save succeeded
*/
virtual bool saveDocument(App::Document* doc) = 0;
/**
* 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)
//@{
/** Commit document changes to external system */
virtual bool commitDocument(App::Document* doc) { (void)doc; return false; }
/** Pull latest changes from external system */
virtual bool pullDocument(App::Document* doc) { (void)doc; return false; }
/** Push local changes to external system */
virtual bool pushDocument(App::Document* doc) { (void)doc; return false; }
/** Show document info dialog */
virtual void showInfo(App::Document* doc) { (void)doc; }
/** Show Bill of Materials dialog */
virtual void showBOM(App::Document* doc) { (void)doc; }
//@}
protected:
FileOrigin() = default;
// Non-copyable
FileOrigin(const FileOrigin&) = delete;
FileOrigin& operator=(const FileOrigin&) = delete;
};
/**
* @brief Local filesystem origin - default origin for local files
*
* This is the default origin that handles documents stored on the
* local filesystem without any external tracking or synchronization.
*/
class GuiExport LocalFileOrigin : public FileOrigin
{
public:
LocalFileOrigin();
~LocalFileOrigin() override = default;
// Identity
std::string id() const override { return "local"; }
std::string name() const override { return "Local Files"; }
std::string nickname() const override { return "Local"; }
QIcon icon() const override;
OriginType type() const override { return OriginType::Local; }
// Characteristics
bool tracksExternally() const override { return false; }
bool requiresAuthentication() const override { return false; }
// Document identity
std::string documentIdentity(App::Document* doc) const override;
std::string documentDisplayId(App::Document* doc) const override;
bool ownsDocument(App::Document* doc) const override;
// 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
#endif // GUI_FILEORIGIN_H