/*************************************************************************** * 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 #include #include #include 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 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