diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index dd4641361c..ca461d7fbb 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -593,6 +593,7 @@ SET(Dialog_CPP_SRCS Dialogs/DlgObjectSelection.cpp Dialogs/DlgAddProperty.cpp VectorListEditor.cpp + OriginManagerDialog.cpp ) SET(Dialog_HPP_SRCS @@ -635,6 +636,7 @@ SET(Dialog_HPP_SRCS Dialogs/DlgObjectSelection.h Dialogs/DlgAddProperty.h VectorListEditor.h + OriginManagerDialog.h ) SET(Dialog_SRCS diff --git a/src/Gui/OriginManagerDialog.cpp b/src/Gui/OriginManagerDialog.cpp new file mode 100644 index 0000000000..28f0111c1d --- /dev/null +++ b/src/Gui/OriginManagerDialog.cpp @@ -0,0 +1,251 @@ +/*************************************************************************** + * 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 +#include +#include +#include + +#include "OriginManagerDialog.h" +#include "OriginManager.h" +#include "FileOrigin.h" +#include "BitmapFactory.h" + + +namespace Gui { + +OriginManagerDialog::OriginManagerDialog(QWidget* parent) + : QDialog(parent) +{ + setupUi(); + populateOriginList(); + updateButtonStates(); +} + +OriginManagerDialog::~OriginManagerDialog() = default; + +void OriginManagerDialog::setupUi() +{ + setWindowTitle(tr("Manage File Origins")); + setMinimumSize(450, 350); + + auto* mainLayout = new QVBoxLayout(this); + + // Description + auto* descLabel = new QLabel(tr("Configure file origins for storing and retrieving documents.")); + descLabel->setWordWrap(true); + mainLayout->addWidget(descLabel); + + // Origin list + m_originList = new QListWidget(this); + m_originList->setIconSize(QSize(24, 24)); + m_originList->setSelectionMode(QAbstractItemView::SingleSelection); + connect(m_originList, &QListWidget::itemSelectionChanged, + this, &OriginManagerDialog::onOriginSelectionChanged); + connect(m_originList, &QListWidget::itemDoubleClicked, + this, &OriginManagerDialog::onOriginDoubleClicked); + mainLayout->addWidget(m_originList); + + // Action buttons + auto* actionLayout = new QHBoxLayout(); + + m_addButton = new QPushButton(tr("Add Silo...")); + m_addButton->setIcon(BitmapFactory().iconFromTheme("list-add")); + connect(m_addButton, &QPushButton::clicked, this, &OriginManagerDialog::onAddSilo); + actionLayout->addWidget(m_addButton); + + m_editButton = new QPushButton(tr("Edit...")); + m_editButton->setIcon(BitmapFactory().iconFromTheme("document-edit")); + connect(m_editButton, &QPushButton::clicked, this, &OriginManagerDialog::onEditOrigin); + actionLayout->addWidget(m_editButton); + + m_removeButton = new QPushButton(tr("Remove")); + m_removeButton->setIcon(BitmapFactory().iconFromTheme("list-remove")); + connect(m_removeButton, &QPushButton::clicked, this, &OriginManagerDialog::onRemoveOrigin); + actionLayout->addWidget(m_removeButton); + + actionLayout->addStretch(); + + m_defaultButton = new QPushButton(tr("Set as Default")); + connect(m_defaultButton, &QPushButton::clicked, this, &OriginManagerDialog::onSetDefault); + actionLayout->addWidget(m_defaultButton); + + mainLayout->addLayout(actionLayout); + + // Dialog buttons + m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + mainLayout->addWidget(m_buttonBox); +} + +void OriginManagerDialog::populateOriginList() +{ + m_originList->clear(); + + auto* mgr = OriginManager::instance(); + std::string currentId = mgr->currentOriginId(); + + for (const std::string& originId : mgr->originIds()) { + FileOrigin* origin = mgr->getOrigin(originId); + if (!origin) { + continue; + } + + auto* item = new QListWidgetItem(m_originList); + item->setIcon(origin->icon()); + + QString displayText = QString::fromStdString(origin->name()); + + // Add connection status for remote origins + if (origin->requiresAuthentication()) { + ConnectionState state = origin->connectionState(); + switch (state) { + case ConnectionState::Connected: + displayText += tr(" [Connected]"); + break; + case ConnectionState::Connecting: + displayText += tr(" [Connecting...]"); + break; + case ConnectionState::Disconnected: + displayText += tr(" [Disconnected]"); + break; + case ConnectionState::Error: + displayText += tr(" [Error]"); + break; + } + } + + // Mark default origin + if (originId == currentId) { + displayText += tr(" (Default)"); + QFont font = item->font(); + font.setBold(true); + item->setFont(font); + } + + item->setText(displayText); + item->setData(Qt::UserRole, QString::fromStdString(originId)); + item->setToolTip(QString::fromStdString(origin->name())); + } +} + +void OriginManagerDialog::updateButtonStates() +{ + FileOrigin* origin = selectedOrigin(); + bool hasSelection = (origin != nullptr); + bool isLocal = hasSelection && (origin->id() == "local"); + bool isDefault = hasSelection && (origin->id() == OriginManager::instance()->currentOriginId()); + + // Can't edit or remove local origin + m_editButton->setEnabled(hasSelection && !isLocal); + m_removeButton->setEnabled(hasSelection && !isLocal); + m_defaultButton->setEnabled(hasSelection && !isDefault); +} + +FileOrigin* OriginManagerDialog::selectedOrigin() const +{ + QListWidgetItem* item = m_originList->currentItem(); + if (!item) { + return nullptr; + } + + std::string originId = item->data(Qt::UserRole).toString().toStdString(); + return OriginManager::instance()->getOrigin(originId); +} + +void OriginManagerDialog::onAddSilo() +{ + // TODO: Open SiloConfigDialog for adding new instance + QMessageBox::information(this, tr("Add Silo"), + tr("Silo configuration dialog not yet implemented.\n\n" + "To add a Silo instance, configure it in the Silo workbench preferences.")); +} + +void OriginManagerDialog::onEditOrigin() +{ + FileOrigin* origin = selectedOrigin(); + if (!origin || origin->id() == "local") { + return; + } + + // TODO: Open SiloConfigDialog for editing + QMessageBox::information(this, tr("Edit Origin"), + tr("Origin editing not yet implemented.\n\n" + "To edit this origin, modify settings in the Silo workbench preferences.")); +} + +void OriginManagerDialog::onRemoveOrigin() +{ + FileOrigin* origin = selectedOrigin(); + if (!origin || origin->id() == "local") { + return; + } + + QString name = QString::fromStdString(origin->name()); + QMessageBox::StandardButton reply = QMessageBox::question(this, + tr("Remove Origin"), + tr("Are you sure you want to remove '%1'?\n\n" + "This will not delete any files, but you will need to reconfigure " + "the connection to use this origin again.").arg(name), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No); + + if (reply == QMessageBox::Yes) { + std::string originId = origin->id(); + OriginManager::instance()->unregisterOrigin(originId); + populateOriginList(); + updateButtonStates(); + } +} + +void OriginManagerDialog::onSetDefault() +{ + FileOrigin* origin = selectedOrigin(); + if (!origin) { + return; + } + + OriginManager::instance()->setCurrentOrigin(origin->id()); + populateOriginList(); + updateButtonStates(); +} + +void OriginManagerDialog::onOriginSelectionChanged() +{ + updateButtonStates(); +} + +void OriginManagerDialog::onOriginDoubleClicked(QListWidgetItem* item) +{ + if (!item) { + return; + } + + std::string originId = item->data(Qt::UserRole).toString().toStdString(); + if (originId != "local") { + onEditOrigin(); + } +} + +} // namespace Gui diff --git a/src/Gui/OriginManagerDialog.h b/src/Gui/OriginManagerDialog.h new file mode 100644 index 0000000000..2e460de258 --- /dev/null +++ b/src/Gui/OriginManagerDialog.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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_ORIGINMANAGERDIALOG_H +#define GUI_ORIGINMANAGERDIALOG_H + +#include +#include +#include +#include +#include + +namespace Gui { + +class FileOrigin; + +/** + * @brief Dialog for managing file origins + * + * This dialog allows users to view, add, edit, and remove file origins + * (Silo instances). The local filesystem origin cannot be removed. + */ +class GuiExport OriginManagerDialog : public QDialog +{ + Q_OBJECT + +public: + explicit OriginManagerDialog(QWidget* parent = nullptr); + ~OriginManagerDialog() override; + +private Q_SLOTS: + void onAddSilo(); + void onEditOrigin(); + void onRemoveOrigin(); + void onSetDefault(); + void onOriginSelectionChanged(); + void onOriginDoubleClicked(QListWidgetItem* item); + +private: + void setupUi(); + void populateOriginList(); + void updateButtonStates(); + FileOrigin* selectedOrigin() const; + + QListWidget* m_originList; + QPushButton* m_addButton; + QPushButton* m_editButton; + QPushButton* m_removeButton; + QPushButton* m_defaultButton; + QDialogButtonBox* m_buttonBox; +}; + +} // namespace Gui + +#endif // GUI_ORIGINMANAGERDIALOG_H diff --git a/src/Gui/OriginSelectorWidget.cpp b/src/Gui/OriginSelectorWidget.cpp index c8a90cb13e..cb2d6b41fe 100644 --- a/src/Gui/OriginSelectorWidget.cpp +++ b/src/Gui/OriginSelectorWidget.cpp @@ -26,6 +26,7 @@ #include "OriginSelectorWidget.h" #include "OriginManager.h" +#include "OriginManagerDialog.h" #include "FileOrigin.h" #include "BitmapFactory.h" @@ -151,8 +152,12 @@ void OriginSelectorWidget::onOriginActionTriggered(QAction* action) void OriginSelectorWidget::onManageOriginsClicked() { - // TODO: Open origins management dialog (Issue #15) - // For now, this is a placeholder + OriginManagerDialog dialog(this); + dialog.exec(); + + // Refresh the menu in case origins changed + rebuildMenu(); + updateDisplay(); } void OriginSelectorWidget::updateDisplay()