Files
create/src/Gui/OriginManager.cpp
forbes 724440dcb7
Some checks failed
Build and Test / build (push) Has been cancelled
fix(gui): fix build errors in OriginSelectorWidget and OriginManager
- OriginSelectorWidget: use BitmapFactoryInst::mergePixmap() instead of
  BitmapFactory::mergePixmap() since BitmapFactory is a function, not a class
- OriginManager: use Console().log() instead of Console().Log() which
  does not exist on ConsoleSingleton
2026-02-05 20:48:28 -06:00

297 lines
8.0 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 *
* *
***************************************************************************/
#include "PreCompiled.h"
#include <App/Application.h>
#include <Base/Console.h>
#include "OriginManager.h"
#include "FileOrigin.h"
namespace Gui {
// Preferences path for origin settings
static const char* PREF_PATH = "User parameter:BaseApp/Preferences/General/Origin";
static const char* PREF_CURRENT_ORIGIN = "CurrentOriginId";
// Built-in origin ID that cannot be unregistered
static const char* LOCAL_ORIGIN_ID = "local";
OriginManager* OriginManager::_instance = nullptr;
OriginManager* OriginManager::instance()
{
if (!_instance) {
_instance = new OriginManager();
}
return _instance;
}
void OriginManager::destruct()
{
delete _instance;
_instance = nullptr;
}
OriginManager::OriginManager()
{
ensureLocalOrigin();
loadPreferences();
}
OriginManager::~OriginManager()
{
savePreferences();
_origins.clear();
}
void OriginManager::ensureLocalOrigin()
{
// Create the built-in local filesystem origin
auto localOrigin = std::make_unique<LocalFileOrigin>();
_origins[LOCAL_ORIGIN_ID] = std::move(localOrigin);
_currentOriginId = LOCAL_ORIGIN_ID;
}
void OriginManager::loadPreferences()
{
try {
auto hGrp = App::GetApplication().GetParameterGroupByPath(PREF_PATH);
std::string savedOriginId = hGrp->GetASCII(PREF_CURRENT_ORIGIN, LOCAL_ORIGIN_ID);
// Only use saved origin if it's registered
if (_origins.find(savedOriginId) != _origins.end()) {
_currentOriginId = savedOriginId;
}
}
catch (...) {
// Ignore preference loading errors
_currentOriginId = LOCAL_ORIGIN_ID;
}
}
void OriginManager::savePreferences()
{
try {
auto hGrp = App::GetApplication().GetParameterGroupByPath(PREF_PATH);
hGrp->SetASCII(PREF_CURRENT_ORIGIN, _currentOriginId.c_str());
}
catch (...) {
// Ignore preference saving errors
}
}
bool OriginManager::registerOrigin(FileOrigin* origin)
{
if (!origin) {
return false;
}
std::string originId = origin->id();
if (originId.empty()) {
Base::Console().warning("OriginManager: Cannot register origin with empty ID\n");
delete origin;
return false;
}
// Check if ID already in use
if (_origins.find(originId) != _origins.end()) {
Base::Console().warning("OriginManager: Origin '%s' already registered\n", originId.c_str());
delete origin;
return false;
}
_origins[originId] = std::unique_ptr<FileOrigin>(origin);
Base::Console().log("OriginManager: Registered origin '%s'\n", originId.c_str());
signalOriginRegistered(originId);
return true;
}
bool OriginManager::unregisterOrigin(const std::string& id)
{
// Cannot unregister the built-in local origin
if (id == LOCAL_ORIGIN_ID) {
Base::Console().warning("OriginManager: Cannot unregister built-in local origin\n");
return false;
}
auto it = _origins.find(id);
if (it == _origins.end()) {
return false;
}
// If unregistering the current origin, switch to local
if (_currentOriginId == id) {
_currentOriginId = LOCAL_ORIGIN_ID;
signalCurrentOriginChanged(_currentOriginId);
}
_origins.erase(it);
Base::Console().log("OriginManager: Unregistered origin '%s'\n", id.c_str());
signalOriginUnregistered(id);
return true;
}
std::vector<std::string> OriginManager::originIds() const
{
std::vector<std::string> ids;
ids.reserve(_origins.size());
for (const auto& pair : _origins) {
ids.push_back(pair.first);
}
return ids;
}
FileOrigin* OriginManager::getOrigin(const std::string& id) const
{
auto it = _origins.find(id);
if (it != _origins.end()) {
return it->second.get();
}
return nullptr;
}
FileOrigin* OriginManager::currentOrigin() const
{
auto it = _origins.find(_currentOriginId);
if (it != _origins.end()) {
return it->second.get();
}
// Fallback to local (should never happen)
return _origins.at(LOCAL_ORIGIN_ID).get();
}
std::string OriginManager::currentOriginId() const
{
return _currentOriginId;
}
bool OriginManager::setCurrentOrigin(const std::string& id)
{
if (_origins.find(id) == _origins.end()) {
return false;
}
if (_currentOriginId != id) {
_currentOriginId = id;
savePreferences();
signalCurrentOriginChanged(_currentOriginId);
}
return true;
}
FileOrigin* OriginManager::findOwningOrigin(App::Document* doc) const
{
if (!doc) {
return nullptr;
}
// Check each origin to see if it owns this document
// Start with non-local origins since they have specific ownership criteria
for (const auto& pair : _origins) {
if (pair.first == LOCAL_ORIGIN_ID) {
continue; // Check local last as fallback
}
if (pair.second->ownsDocument(doc)) {
return pair.second.get();
}
}
// If no PLM origin claims it, check local
auto localIt = _origins.find(LOCAL_ORIGIN_ID);
if (localIt != _origins.end() && localIt->second->ownsDocument(doc)) {
return localIt->second.get();
}
return nullptr;
}
FileOrigin* OriginManager::originForDocument(App::Document* doc) const
{
if (!doc) {
return nullptr;
}
// Check explicit association first
auto it = _documentOrigins.find(doc);
if (it != _documentOrigins.end()) {
FileOrigin* origin = getOrigin(it->second);
if (origin) {
return origin;
}
// Origin was unregistered, clear stale association
_documentOrigins.erase(it);
}
// Fall back to ownership detection
FileOrigin* owner = findOwningOrigin(doc);
if (owner) {
// Cache the result
_documentOrigins[doc] = owner->id();
return owner;
}
return nullptr;
}
void OriginManager::setDocumentOrigin(App::Document* doc, FileOrigin* origin)
{
if (!doc) {
return;
}
std::string originId = origin ? origin->id() : "";
if (origin) {
_documentOrigins[doc] = originId;
} else {
_documentOrigins.erase(doc);
}
signalDocumentOriginChanged(doc, originId);
}
void OriginManager::clearDocumentOrigin(App::Document* doc)
{
if (!doc) {
return;
}
auto it = _documentOrigins.find(doc);
if (it != _documentOrigins.end()) {
_documentOrigins.erase(it);
}
}
FileOrigin* OriginManager::originForNewDocument() const
{
return currentOrigin();
}
} // namespace Gui