Internal
Public Access
ProfileRepository::deleteFolder() removes a folder without ever deleting
the profiles or subfolders inside it -- everything directly under the
deleted folder shifts up to take its place (its parent, or the top level
if it had none), exactly as if that one path segment were removed from
each affected path. This is a labels-only operation (a "folder" is just a
grouping string on each profile, not a container that owns them), so
that's the least-surprising behavior versus silently bulk-deleting saved
connections.
Right-clicking a folder in the tree now offers "Delete Folder"; if it
isn't empty, a confirmation states exactly how many profiles/subfolders
will move and to where.
Covered by 7 new unit tests, which caught the same class of bug fixed in
3fab2f9: the new code's own folder-path remap also bound an unguarded
null QString (a folder moving to root) against the `folder_path NOT
NULL` column.
Fixes #20.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
83 lines
2.5 KiB
C++
83 lines
2.5 KiB
C++
#ifndef ORBITHUB_PROFILES_WINDOW_H
|
|
#define ORBITHUB_PROFILES_WINDOW_H
|
|
|
|
#include "profile_repository.h"
|
|
|
|
#include <QWidget>
|
|
#include <QString>
|
|
#include <QStringList>
|
|
#include <QtGlobal>
|
|
|
|
#include <memory>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
|
|
class QTreeWidget;
|
|
class QTreeWidgetItem;
|
|
class QLineEdit;
|
|
class QPushButton;
|
|
class QComboBox;
|
|
class QPoint;
|
|
class ProfilesTreeWidget;
|
|
|
|
class ProfilesWindow : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit ProfilesWindow(QWidget* parent = nullptr);
|
|
~ProfilesWindow() override;
|
|
|
|
void createProfileInCurrentContext();
|
|
void createFolderInCurrentContext();
|
|
void exportProfiles();
|
|
void importProfiles();
|
|
|
|
signals:
|
|
void connectRequested(const Profile& profile);
|
|
|
|
private:
|
|
QLineEdit* m_searchBox;
|
|
QComboBox* m_viewModeBox;
|
|
QComboBox* m_sortBox;
|
|
QComboBox* m_protocolFilterBox;
|
|
QComboBox* m_tagFilterBox;
|
|
ProfilesTreeWidget* m_profilesTree;
|
|
QPushButton* m_newButton;
|
|
QPushButton* m_editButton;
|
|
QPushButton* m_deleteButton;
|
|
std::unique_ptr<ProfileRepository> m_repository;
|
|
std::unordered_map<qint64, Profile> m_profileCache;
|
|
QString m_pendingTagFilterPreference;
|
|
|
|
void setupUi();
|
|
void loadProfiles();
|
|
ProfileSortOrder selectedSortOrder() const;
|
|
bool isFolderViewEnabled() const;
|
|
QString selectedProtocolFilter() const;
|
|
QString selectedTagFilter() const;
|
|
void updateTagFilterOptions(const std::vector<Profile>& profiles);
|
|
QTreeWidgetItem* upsertFolderNode(const QStringList& folderParts,
|
|
std::map<QString, QTreeWidgetItem*>& folderNodes);
|
|
void addProfileNode(QTreeWidgetItem* parent, const Profile& profile);
|
|
QString folderPathForItem(const QTreeWidgetItem* item) const;
|
|
void showTreeContextMenu(const QPoint& pos);
|
|
void createFolderInContext(const QString& baseFolderPath);
|
|
void deleteFolderInContext(const QString& folderPath);
|
|
void persistFolderAssignmentsFromTree();
|
|
void collectProfileAssignments(const QTreeWidgetItem* item,
|
|
const QString& parentFolderPath,
|
|
std::unordered_map<qint64, QString>& assignments) const;
|
|
void loadUiPreferences();
|
|
void saveUiPreferences() const;
|
|
std::optional<Profile> selectedProfile() const;
|
|
void createProfile(const QString& defaultFolderPath = QString());
|
|
void editSelectedProfile();
|
|
void deleteSelectedProfile();
|
|
void openSessionForItem(QTreeWidgetItem* item);
|
|
};
|
|
|
|
#endif
|