diff --git a/src/admc/central_widget.cpp b/src/admc/central_widget.cpp index 987d8a41..636b6b08 100644 --- a/src/admc/central_widget.cpp +++ b/src/admc/central_widget.cpp @@ -69,8 +69,15 @@ CentralWidget::CentralWidget(AdInterface &ad) console_actions = new ConsoleActions(this); open_filter_action = new QAction(tr("&Filter objects"), this); - dev_mode_action = new QAction(tr("Dev mode"), this); - show_noncontainers_action = new QAction(tr("&Show non-container objects in Console tree"), this); + + // NOTE: these actions are not connected here because + // they need to be connected to a custom slot + dev_mode_action = settings_make_action(BoolSetting_DevMode, tr("Dev mode"), this); + show_noncontainers_action = settings_make_action(BoolSetting_ShowNonContainersInConsoleTree, tr("&Show non-container objects in Console tree"), this); + advanced_features_action = settings_make_action(BoolSetting_AdvancedFeatures, tr("Advanced features"), this); + + toggle_console_tree_action = settings_make_and_connect_action(BoolSetting_AdvancedFeatures, tr("Console Tree"), this); + toggle_description_bar_action = settings_make_and_connect_action(BoolSetting_ShowResultsHeader, tr("Description Bar"), this); console = new ConsoleWidget(); @@ -105,37 +112,28 @@ CentralWidget::CentralWidget(AdInterface &ad) setLayout(layout); layout->addWidget(console); - const QVariant console_widget_state = g_settings->get_variant(VariantSetting_ConsoleWidgetState); + const QVariant console_widget_state = settings_get_variant(VariantSetting_ConsoleWidgetState); console->restore_state(console_widget_state); - const QVariant policy_results_state = g_settings->get_variant(VariantSetting_PolicyResultsState); - policy_results_widget->restore_state(policy_results_state); - - const QVariant filter_dialog_state = g_settings->get_variant(VariantSetting_FilterDialogState); - filter_dialog->restore_state(filter_dialog_state); - - // Refresh head when settings affecting the filter - // change. This reloads the model with an updated filter - const BoolSettingSignal *advanced_features = g_settings->get_bool_signal(BoolSetting_AdvancedFeatures); connect( - advanced_features, &BoolSettingSignal::changed, - this, &CentralWidget::refresh_head); - - const BoolSettingSignal *show_non_containers = g_settings->get_bool_signal(BoolSetting_ShowNonContainersInConsoleTree); + show_noncontainers_action, &QAction::toggled, + this, &CentralWidget::on_show_non_containers); + on_show_non_containers(); + connect( - show_non_containers, &BoolSettingSignal::changed, - this, &CentralWidget::refresh_head); + dev_mode_action, &QAction::toggled, + this, &CentralWidget::on_dev_mode); + on_dev_mode(); - const BoolSettingSignal *dev_mode_signal = g_settings->get_bool_signal(BoolSetting_DevMode); connect( - dev_mode_signal, &BoolSettingSignal::changed, - this, &CentralWidget::refresh_head); + toggle_console_tree_action, &QAction::toggled, + this, &CentralWidget::on_toggle_console_tree); + on_toggle_console_tree(); - g_settings->connect_toggle_widget(console->get_scope_view(), BoolSetting_ShowConsoleTree); - g_settings->connect_toggle_widget(console->get_description_bar(), BoolSetting_ShowResultsHeader); - - g_settings->connect_action_to_bool_setting(dev_mode_action, BoolSetting_DevMode); - g_settings->connect_action_to_bool_setting(show_noncontainers_action, BoolSetting_ShowNonContainersInConsoleTree); + connect( + toggle_description_bar_action, &QAction::toggled, + this, &CentralWidget::on_toggle_description_bar); + on_toggle_description_bar(); connect( open_filter_action, &QAction::triggered, @@ -262,15 +260,9 @@ CentralWidget::CentralWidget(AdInterface &ad) console->set_current_scope(console_object_head()->index()); } -void CentralWidget::save_state() { - const QVariant console_widget_state = console->save_state(); - g_settings->set_variant(VariantSetting_ConsoleWidgetState, console_widget_state); - - const QVariant policy_results_state = policy_results_widget->save_state(); - g_settings->set_variant(VariantSetting_PolicyResultsState, policy_results_state); - - const QVariant filter_dialog_state = filter_dialog->save_state(); - g_settings->set_variant(VariantSetting_FilterDialogState, filter_dialog_state); +CentralWidget::~CentralWidget() { + const QVariant state = console->save_state(); + settings_set_variant(VariantSetting_ConsoleWidgetState, state); } void CentralWidget::object_delete() { @@ -722,6 +714,34 @@ void CentralWidget::on_object_properties_applied() { update_actions_visibility(); } +void CentralWidget::on_show_non_containers() { + settings_set_bool(BoolSetting_ShowNonContainersInConsoleTree, show_noncontainers_action->isChecked()); + + refresh_head(); +} + +void CentralWidget::on_dev_mode() { + settings_set_bool(BoolSetting_DevMode, dev_mode_action->isChecked()); + + refresh_head(); +} + +void CentralWidget::on_advanced_features() { + settings_set_bool(BoolSetting_AdvancedFeatures, advanced_features_action->isChecked()); + + refresh_head(); +} + +void CentralWidget::on_toggle_console_tree() { + const bool visible = toggle_console_tree_action->isChecked(); + console->get_scope_view()->setVisible(visible); +} + +void CentralWidget::on_toggle_description_bar() { + const bool visible = toggle_description_bar_action->isChecked(); + console->get_description_bar()->setVisible(visible); +} + void CentralWidget::refresh_head() { show_busy_indicator(); @@ -753,30 +773,34 @@ void CentralWidget::update_description_bar() { console->set_description_bar_text(text); } -void CentralWidget::add_actions_to_action_menu(QMenu *menu) { - console_actions->add_to_menu(menu); +void CentralWidget::add_actions_to_menus(QMenu *action_menu, QMenu *navigation_menu, QMenu *view_menu, QMenu *preferences_menu) { + // Action + console_actions->add_to_menu(action_menu); - menu->addSeparator(); + action_menu->addSeparator(); - console->add_actions_to_action_menu(menu); -} + console->add_actions_to_action_menu(action_menu); -void CentralWidget::add_actions_to_navigation_menu(QMenu *menu) { - console->add_actions_to_navigation_menu(menu); -} + // Navigation + console->add_actions_to_navigation_menu(navigation_menu); -void CentralWidget::add_actions_to_view_menu(QMenu *menu) { - console->add_actions_to_view_menu(menu); + // View + console->add_actions_to_view_menu(view_menu); - menu->addSeparator(); + view_menu->addSeparator(); - menu->addAction(open_filter_action); + view_menu->addAction(open_filter_action); - menu->addAction(show_noncontainers_action); + view_menu->addAction(show_noncontainers_action); #ifdef QT_DEBUG - menu->addAction(dev_mode_action); + view_menu->addAction(dev_mode_action); #endif + + // Preferences + preferences_menu->addAction(advanced_features_action); + preferences_menu->addAction(toggle_console_tree_action); + preferences_menu->addAction(toggle_description_bar_action); } void CentralWidget::fetch_scope_node(const QModelIndex &index) { diff --git a/src/admc/central_widget.h b/src/admc/central_widget.h index 326f7cdb..44d9e1ca 100644 --- a/src/admc/central_widget.h +++ b/src/admc/central_widget.h @@ -63,11 +63,9 @@ class CentralWidget final : public QWidget { public: CentralWidget(AdInterface &ad); - void save_state(); + ~CentralWidget(); - void add_actions_to_action_menu(QMenu *menu); - void add_actions_to_navigation_menu(QMenu *menu); - void add_actions_to_view_menu(QMenu *menu); + void add_actions_to_menus(QMenu *action_menu, QMenu *navigation_menu, QMenu *view_menu, QMenu *preferences_menu); signals: void context_menu(const QPoint pos); @@ -108,6 +106,12 @@ private slots: void on_current_scope_changed(); void on_object_properties_applied(); + void on_show_non_containers(); + void on_dev_mode(); + void on_advanced_features(); + void on_toggle_console_tree(); + void on_toggle_description_bar(); + private: ConsoleWidget *console; FilterDialog *filter_dialog; @@ -118,6 +122,9 @@ private: QAction *open_filter_action; QAction *show_noncontainers_action; QAction *dev_mode_action; + QAction *advanced_features_action; + QAction *toggle_console_tree_action; + QAction *toggle_description_bar_action; void update_description_bar(); void enable_disable_helper(const bool disabled); diff --git a/src/admc/change_dc_dialog.cpp b/src/admc/change_dc_dialog.cpp index c1f22b97..2b8f7652 100644 --- a/src/admc/change_dc_dialog.cpp +++ b/src/admc/change_dc_dialog.cpp @@ -77,7 +77,7 @@ void ChangeDCDialog::accept() { console_object_load_domain_head_text(domain_head_item); if (save_dc_checkbox->isChecked()) { - g_settings->set_variant(VariantSetting_DC, current_dc); + settings_set_variant(VariantSetting_DC, current_dc); } QDialog::accept(); diff --git a/src/admc/console_types/console_object.cpp b/src/admc/console_types/console_object.cpp index 9e40e992..496d854f 100644 --- a/src/admc/console_types/console_object.cpp +++ b/src/admc/console_types/console_object.cpp @@ -270,7 +270,7 @@ void console_object_create(ConsoleWidget *console, const QList &object return filter_containers.contains(object_class); }(); - const bool show_non_containers_ON = g_settings->get_bool(BoolSetting_ShowNonContainersInConsoleTree); + const bool show_non_containers_ON = settings_get_bool(BoolSetting_ShowNonContainersInConsoleTree); return (is_container || show_non_containers_ON); }(); @@ -377,7 +377,7 @@ void console_object_fetch(ConsoleWidget *console, const QString ¤t_filter, // NOTE: do an extra search before real search for // objects that should be visible in dev mode - const bool dev_mode = g_settings->get_bool(BoolSetting_DevMode); + const bool dev_mode = settings_get_bool(BoolSetting_DevMode); if (dev_mode) { AdInterface ad; if (ad_connected(ad)) { diff --git a/src/admc/console_types/console_query.cpp b/src/admc/console_types/console_query.cpp index 383db0d2..fd62fb87 100644 --- a/src/admc/console_types/console_query.cpp +++ b/src/admc/console_types/console_query.cpp @@ -175,8 +175,8 @@ void console_query_tree_init(ConsoleWidget *console) { query_tree_head->setDragEnabled(false); // Add rest of tree - const QHash folder_list = g_settings->get_variant(VariantSetting_QueryFolders).toHash(); - const QHash item_list = g_settings->get_variant(VariantSetting_QueryItems).toHash(); + const QHash folder_list = settings_get_variant(VariantSetting_QueryFolders).toHash(); + const QHash item_list = settings_get_variant(VariantSetting_QueryItems).toHash(); QStack folder_stack; folder_stack.append(query_tree_head->index()); @@ -274,8 +274,8 @@ void console_query_tree_save(ConsoleWidget *console) { const QVariant folder_variant = QVariant(folder_list); const QVariant item_variant = QVariant(item_list); - g_settings->set_variant(VariantSetting_QueryFolders, folder_variant); - g_settings->set_variant(VariantSetting_QueryItems, item_variant); + settings_set_variant(VariantSetting_QueryFolders, folder_variant); + settings_set_variant(VariantSetting_QueryItems, item_variant); } bool console_query_or_folder_name_is_good(ConsoleWidget *console, const QString &name, const QModelIndex &parent_index, QWidget *parent_widget, const QModelIndex ¤t_index) { diff --git a/src/admc/create_object_dialog.cpp b/src/admc/create_object_dialog.cpp index 98b187a6..3e7ebd8b 100644 --- a/src/admc/create_object_dialog.cpp +++ b/src/admc/create_object_dialog.cpp @@ -118,7 +118,7 @@ CreateObjectDialog::CreateObjectDialog(const QString &parent_dn_arg, const QStri const QString first_name = first_name_edit->get_input(); const QString last_name = last_name_edit->get_input(); - const bool last_name_first = g_settings->get_bool(BoolSetting_LastNameBeforeFirstName); + const bool last_name_first = settings_get_bool(BoolSetting_LastNameBeforeFirstName); if (!first_name.isEmpty() && !last_name.isEmpty()) { if (last_name_first) { return last_name + " " + first_name; diff --git a/src/admc/filter_dialog.cpp b/src/admc/filter_dialog.cpp index 1f80e790..674f9579 100644 --- a/src/admc/filter_dialog.cpp +++ b/src/admc/filter_dialog.cpp @@ -89,7 +89,7 @@ FilterDialog::FilterDialog(QWidget *parent) layout->addWidget(radio_buttons_frame); layout->addWidget(button_box); - g_settings->setup_dialog_geometry(VariantSetting_FilterDialogGeometry, this); + settings_setup_dialog_geometry(VariantSetting_FilterDialogGeometry, this); button_state_name_map = { {"ALL_BUTTON_STATE", all_button}, @@ -97,6 +97,18 @@ FilterDialog::FilterDialog(QWidget *parent) {"CUSTOM_BUTTON_STATE", custom_button}, }; + const QHash state = settings_get_variant(VariantSetting_FilterDialogState).toHash(); + + filter_widget->restore_state(state[FILTER_WIDGET_STATE]); + filter_classes_widget->restore_state(state[FILTER_CLASSES_STATE]); + + for (const QString &state_name : button_state_name_map.keys()) { + QRadioButton *button = button_state_name_map[state_name]; + + const QVariant button_state = state[state_name]; + button->setChecked(button_state.toBool()); + } + connect( button_box, &QDialogButtonBox::accepted, this, &QDialog::accept); @@ -119,7 +131,7 @@ bool FilterDialog::filtering_ON() const { return !all_button->isChecked(); } -QVariant FilterDialog::save_state() const { +FilterDialog::~FilterDialog() { QHash state; state[FILTER_WIDGET_STATE] = filter_widget->save_state(); @@ -131,21 +143,7 @@ QVariant FilterDialog::save_state() const { state[state_name] = button->isChecked(); } - return QVariant(state); -} - -void FilterDialog::restore_state(const QVariant &state_variant) { - const QHash state = state_variant.toHash(); - - filter_widget->restore_state(state[FILTER_WIDGET_STATE]); - filter_classes_widget->restore_state(state[FILTER_CLASSES_STATE]); - - for (const QString &state_name : button_state_name_map.keys()) { - QRadioButton *button = button_state_name_map[state_name]; - - const QVariant button_state = state[state_name]; - button->setChecked(button_state.toBool()); - } + settings_set_variant(VariantSetting_FilterDialogState, state); } QString FilterDialog::get_filter() const { diff --git a/src/admc/filter_dialog.h b/src/admc/filter_dialog.h index c91df754..17d960cd 100644 --- a/src/admc/filter_dialog.h +++ b/src/admc/filter_dialog.h @@ -40,13 +40,11 @@ class FilterDialog final : public QDialog { public: FilterDialog(QWidget *parent); + ~FilterDialog(); QString get_filter() const; bool filtering_ON() const; - QVariant save_state() const; - void restore_state(const QVariant &state); - private: FilterCustomDialog *custom_dialog; QRadioButton *all_button; diff --git a/src/admc/find_object_dialog.cpp b/src/admc/find_object_dialog.cpp index 6696af61..a41a4754 100644 --- a/src/admc/find_object_dialog.cpp +++ b/src/admc/find_object_dialog.cpp @@ -49,5 +49,5 @@ FindObjectDialog::FindObjectDialog(const QList classes, const QString d find_widget->find_results->add_actions_to_action_menu(action_menu); find_widget->find_results->add_actions_to_view_menu(view_menu); - g_settings->setup_dialog_geometry(VariantSetting_FindObjectDialogGeometry, this); + settings_setup_dialog_geometry(VariantSetting_FindObjectDialogGeometry, this); } diff --git a/src/admc/find_results.cpp b/src/admc/find_results.cpp index 635ec4b1..f4e27887 100644 --- a/src/admc/find_results.cpp +++ b/src/admc/find_results.cpp @@ -71,7 +71,7 @@ FindResults::FindResults() customize_columns_action = new QAction(tr("&Customize columns"), this); - const QVariant view_state = g_settings->get_variant(VariantSetting_FindResultsViewState); + const QVariant view_state = settings_get_variant(VariantSetting_FindResultsViewState); view->restore_state(view_state, console_object_default_columns()); connect( @@ -121,7 +121,7 @@ FindResults::FindResults() FindResults::~FindResults() { const QVariant view_state = view->save_state(); - g_settings->set_variant(VariantSetting_FindResultsViewState, view_state); + settings_set_variant(VariantSetting_FindResultsViewState, view_state); } void FindResults::add_actions_to_action_menu(QMenu *menu) { diff --git a/src/admc/globals.cpp b/src/admc/globals.cpp index 10122e62..58c8973c 100644 --- a/src/admc/globals.cpp +++ b/src/admc/globals.cpp @@ -21,11 +21,9 @@ #include "globals.h" #include "adldap.h" -#include "settings.h" #include "status.h" AdConfig *g_adconfig = new AdConfig(); -Settings *g_settings = new Settings(); // NOTE: status has to be in a function because it creates a // widget so needs to be created after app is created diff --git a/src/admc/globals.h b/src/admc/globals.h index 125af602..ca3e00f1 100644 --- a/src/admc/globals.h +++ b/src/admc/globals.h @@ -22,11 +22,9 @@ #define GLOBALS_H class AdConfig; -class Settings; class Status; extern AdConfig *g_adconfig; -extern Settings *g_settings; Status *g_status(); #endif /* GLOBALS_H */ diff --git a/src/admc/main.cpp b/src/admc/main.cpp index ae4a50a3..d5d71613 100644 --- a/src/admc/main.cpp +++ b/src/admc/main.cpp @@ -45,7 +45,7 @@ int main(int argc, char **argv) { app.setOrganizationName(ADMC_ORGANIZATION); app.setOrganizationDomain(ADMC_ORGANIZATION_DOMAIN); - const QLocale saved_locale = g_settings->get_variant(VariantSetting_Locale).toLocale(); + const QLocale saved_locale = settings_get_variant(VariantSetting_Locale).toLocale(); QTranslator translator; const bool loaded_admc_translation = translator.load(saved_locale, "admc", "_", ":/admc"); diff --git a/src/admc/main_window.cpp b/src/admc/main_window.cpp index 95a16c84..f70b868f 100644 --- a/src/admc/main_window.cpp +++ b/src/admc/main_window.cpp @@ -41,8 +41,6 @@ MainWindow::MainWindow() : QMainWindow() { - central_widget = nullptr; - setStatusBar(g_status()->status_bar()); message_log_dock = new QDockWidget(); @@ -56,13 +54,13 @@ MainWindow::MainWindow() setup_menubar(); - const bool restored_geometry = g_settings->restore_geometry(VariantSetting_MainWindowGeometry, this); + const bool restored_geometry = settings_restore_geometry(VariantSetting_MainWindowGeometry, this); if (!restored_geometry) { resize(1024, 768); } - if (g_settings->contains_variant(VariantSetting_MainWindowState)) { - const QByteArray state = g_settings->get_variant(VariantSetting_MainWindowState).toByteArray(); + const QByteArray state = settings_get_variant(VariantSetting_MainWindowState).toByteArray(); + if (!state.isEmpty()) { restoreState(state); } else { message_log_dock->hide(); @@ -72,14 +70,11 @@ MainWindow::MainWindow() } void MainWindow::closeEvent(QCloseEvent *event) { - g_settings->save_geometry(VariantSetting_MainWindowGeometry, this); + const QByteArray geometry = saveGeometry(); + settings_set_variant(VariantSetting_MainWindowGeometry, geometry); const QByteArray state = saveState(); - g_settings->set_variant(VariantSetting_MainWindowState, state); - - if (central_widget != nullptr) { - central_widget->save_state(); - } + settings_set_variant(VariantSetting_MainWindowState, state); QMainWindow::closeEvent(event); } @@ -101,13 +96,10 @@ void MainWindow::setup_menubar() { auto manual_action = new QAction(tr("&Manual"), this); auto about_action = new QAction(tr("&About ADMC"), this); - auto advanced_features_action = new QAction(tr("&Advanced Features"), this); - auto confirm_actions_action = new QAction(tr("&Confirm actions"), this); - auto last_before_first_name_action = new QAction(tr("&Put last name before first name when creating users"), this); - auto log_searches_action = new QAction(tr("Log searches"), this); - auto timestamp_log_action = new QAction(tr("Timestamps in message log"), this); - auto toggle_console_tree_action = new QAction(tr("Console Tree"), this); - auto toggle_description_bar_action = new QAction(tr("Description Bar"), this); + auto confirm_actions_action = settings_make_and_connect_action(BoolSetting_ConfirmActions, tr("&Confirm actions"), this); + auto last_before_first_name_action = settings_make_and_connect_action(BoolSetting_LastNameBeforeFirstName, tr("&Put last name before first name when creating users"), this); + auto log_searches_action = settings_make_and_connect_action(BoolSetting_LogSearches, tr("Log searches"), this); + auto timestamp_log_action = settings_make_and_connect_action(BoolSetting_TimestampLog, tr("Timestamps in message log"), this); const QList language_list = { QLocale::English, @@ -135,7 +127,7 @@ void MainWindow::setup_menubar() { language_group->addAction(action); const bool is_checked = [=]() { - const QLocale current_locale = g_settings->get_variant(VariantSetting_Locale).toLocale(); + const QLocale current_locale = settings_get_variant(VariantSetting_Locale).toLocale(); return (current_locale == locale); }(); @@ -157,7 +149,7 @@ void MainWindow::setup_menubar() { action_menu = menubar->addMenu(tr("&Action")); navigation_menu = menubar->addMenu(tr("&Navigation")); view_menu = menubar->addMenu(tr("&View")); - auto preferences_menu = menubar->addMenu(tr("&Preferences")); + preferences_menu = menubar->addMenu(tr("&Preferences")); auto language_menu = new QMenu(tr("&Language")); auto help_menu = menubar->addMenu(tr("&Help")); @@ -167,7 +159,6 @@ void MainWindow::setup_menubar() { file_menu->addAction(connect_action); file_menu->addAction(quit_action); - preferences_menu->addAction(advanced_features_action); preferences_menu->addAction(confirm_actions_action); preferences_menu->addAction(last_before_first_name_action); preferences_menu->addAction(log_searches_action); @@ -175,8 +166,6 @@ void MainWindow::setup_menubar() { preferences_menu->addMenu(language_menu); preferences_menu->addSeparator(); preferences_menu->addAction(message_log_dock->toggleViewAction()); - preferences_menu->addAction(toggle_console_tree_action); - preferences_menu->addAction(toggle_description_bar_action); for (const auto language : language_list) { QAction *language_action = language_actions[language]; @@ -202,13 +191,6 @@ void MainWindow::setup_menubar() { connect( about_action, &QAction::triggered, about_dialog, &QDialog::open); - g_settings->connect_action_to_bool_setting(advanced_features_action, BoolSetting_AdvancedFeatures); - g_settings->connect_action_to_bool_setting(confirm_actions_action, BoolSetting_ConfirmActions); - g_settings->connect_action_to_bool_setting(last_before_first_name_action, BoolSetting_LastNameBeforeFirstName); - g_settings->connect_action_to_bool_setting(log_searches_action, BoolSetting_LogSearches); - g_settings->connect_action_to_bool_setting(timestamp_log_action, BoolSetting_TimestampLog); - g_settings->connect_action_to_bool_setting(toggle_console_tree_action, BoolSetting_ShowConsoleTree); - g_settings->connect_action_to_bool_setting(toggle_description_bar_action, BoolSetting_ShowResultsHeader); for (const auto language : language_actions.keys()) { QAction *action = language_actions[language]; @@ -217,7 +199,7 @@ void MainWindow::setup_menubar() { action, &QAction::toggled, [this, language](bool checked) { if (checked) { - g_settings->set_variant(VariantSetting_Locale, QLocale(language)); + settings_set_variant(VariantSetting_Locale, QLocale(language)); message_box_information(this, tr("Info"), tr("Restart the app to switch to the selected language.")); } @@ -225,19 +207,19 @@ void MainWindow::setup_menubar() { } connect( - g_settings->get_bool_signal(BoolSetting_LogSearches), &BoolSettingSignal::changed, + log_searches_action, &QAction::toggled, this, &MainWindow::on_log_searches_changed); on_log_searches_changed(); } void MainWindow::connect_to_server() { - const QString saved_dc = g_settings->get_variant(VariantSetting_DC).toString(); + const QString saved_dc = settings_get_variant(VariantSetting_DC).toString(); AdInterface::set_dc(saved_dc); AdInterface ad; if (ad_connected(ad)) { // TODO: check for load failure - const QLocale locale = g_settings->get_variant(VariantSetting_Locale).toLocale(); + const QLocale locale = settings_get_variant(VariantSetting_Locale).toLocale(); g_adconfig->load(ad, locale); qDebug() << "domain =" << g_adconfig->domain(); @@ -246,20 +228,17 @@ void MainWindow::connect_to_server() { g_status()->display_ad_messages(ad, this); - central_widget = new CentralWidget(ad); + auto central_widget = new CentralWidget(ad); setCentralWidget(central_widget); - central_widget->add_actions_to_action_menu(action_menu); - central_widget->add_actions_to_navigation_menu(navigation_menu); - central_widget->add_actions_to_view_menu(view_menu); + central_widget->add_actions_to_menus(action_menu, navigation_menu, view_menu, preferences_menu); - central_widget->setEnabled(true); connect_action->setEnabled(false); } } void MainWindow::on_log_searches_changed() { - const bool log_searches_ON = g_settings->get_bool(BoolSetting_LogSearches); + const bool log_searches_ON = settings_get_bool(BoolSetting_LogSearches); AdInterface::set_log_searches(log_searches_ON); } diff --git a/src/admc/main_window.h b/src/admc/main_window.h index 682eab38..82612198 100644 --- a/src/admc/main_window.h +++ b/src/admc/main_window.h @@ -24,7 +24,6 @@ #include class QAction; -class CentralWidget; class QDockWidget; class QMenu; @@ -39,12 +38,12 @@ protected: private: QAction *connect_action; - CentralWidget *central_widget; QDockWidget *message_log_dock; QMenu *action_menu; QMenu *navigation_menu; QMenu *view_menu; + QMenu *preferences_menu; void setup_menubar(); void connect_to_server(); diff --git a/src/admc/object_multi_properties_dialog.cpp b/src/admc/object_multi_properties_dialog.cpp index 22d53563..6201dbf9 100644 --- a/src/admc/object_multi_properties_dialog.cpp +++ b/src/admc/object_multi_properties_dialog.cpp @@ -80,7 +80,7 @@ ObjectMultiPropertiesDialog::ObjectMultiPropertiesDialog(const QList &t add_tab(new OrganizationMultiTab(), tr("Organization")); } - g_settings->setup_dialog_geometry(VariantSetting_ObjectMultiDialogGeometry, this); + settings_setup_dialog_geometry(VariantSetting_ObjectMultiDialogGeometry, this); for (PropertiesMultiTab *tab : tab_list) { connect( diff --git a/src/admc/policy_results_widget.cpp b/src/admc/policy_results_widget.cpp index a1eff02f..9d607a3c 100644 --- a/src/admc/policy_results_widget.cpp +++ b/src/admc/policy_results_widget.cpp @@ -29,6 +29,7 @@ #include "gplink.h" #include "status.h" #include "utils.h" +#include "settings.h" #include #include @@ -97,6 +98,14 @@ PolicyResultsWidget::PolicyResultsWidget() { layout->setSpacing(0); layout->addWidget(view); + const QVariant state = settings_get_variant(VariantSetting_PolicyResultsState); + view->restore_state(state, { + PolicyResultsColumn_Name, + PolicyResultsColumn_Enforced, + PolicyResultsColumn_Disabled, + PolicyResultsColumn_Path, + }); + connect( model, &QStandardItemModel::itemChanged, this, &PolicyResultsWidget::on_item_changed); @@ -108,19 +117,9 @@ PolicyResultsWidget::PolicyResultsWidget() { this, &PolicyResultsWidget::delete_link); } -QVariant PolicyResultsWidget::save_state() { - const QVariant view_state = view->save_state(); - - return view_state; -} - -void PolicyResultsWidget::restore_state(const QVariant &state) { - view->restore_state(state, { - PolicyResultsColumn_Name, - PolicyResultsColumn_Enforced, - PolicyResultsColumn_Disabled, - PolicyResultsColumn_Path, - }); +PolicyResultsWidget::~PolicyResultsWidget() { + const QVariant state = view->save_state(); + settings_set_variant(VariantSetting_PolicyResultsState, state); } void PolicyResultsWidget::update(const QModelIndex &index) { diff --git a/src/admc/policy_results_widget.h b/src/admc/policy_results_widget.h index d54e92bd..fd286cd1 100644 --- a/src/admc/policy_results_widget.h +++ b/src/admc/policy_results_widget.h @@ -37,9 +37,7 @@ class PolicyResultsWidget final : public QWidget { public: PolicyResultsWidget(); - - QVariant save_state(); - void restore_state(const QVariant &state); + ~PolicyResultsWidget(); // Loads links for this policy. Nothing is done if given // index is not a policy. diff --git a/src/admc/properties_dialog.cpp b/src/admc/properties_dialog.cpp index 5a20d87a..aa8ac318 100644 --- a/src/admc/properties_dialog.cpp +++ b/src/admc/properties_dialog.cpp @@ -154,7 +154,7 @@ PropertiesDialog::PropertiesDialog(const QString &target_arg) add_tab(new GeneralTab(object), tr("General")); - const bool advanced_view_ON = g_settings->get_bool(BoolSetting_AdvancedFeatures); + const bool advanced_view_ON = settings_get_bool(BoolSetting_AdvancedFeatures); if (advanced_view_ON) { add_tab(new ObjectTab(), tr("Object")); @@ -213,7 +213,7 @@ PropertiesDialog::PropertiesDialog(const QString &target_arg) reset_internal(ad); } - g_settings->setup_dialog_geometry(VariantSetting_PropertiesDialogGeometry, this); + settings_setup_dialog_geometry(VariantSetting_PropertiesDialogGeometry, this); connect( ok_button, &QPushButton::clicked, diff --git a/src/admc/select_container_dialog.cpp b/src/admc/select_container_dialog.cpp index 849b37a6..4c10612e 100644 --- a/src/admc/select_container_dialog.cpp +++ b/src/admc/select_container_dialog.cpp @@ -93,7 +93,7 @@ SelectContainerDialog::SelectContainerDialog(QWidget *parent) // NOTE: geometry is shared with the subclass // MoveObjectDialog but that is intended. - g_settings->setup_dialog_geometry(VariantSetting_SelectContainerDialogGeometry, this); + settings_setup_dialog_geometry(VariantSetting_SelectContainerDialogGeometry, this); connect( button_box, &QDialogButtonBox::accepted, diff --git a/src/admc/select_object_dialog.cpp b/src/admc/select_object_dialog.cpp index 3b2a075b..3747ea66 100644 --- a/src/admc/select_object_dialog.cpp +++ b/src/admc/select_object_dialog.cpp @@ -122,9 +122,9 @@ SelectObjectDialog::SelectObjectDialog(const QList class_list_arg, cons layout->addLayout(object_view_layout); layout->addWidget(button_box); - g_settings->setup_dialog_geometry(VariantSetting_SelectObjectDialogGeometry, this); + settings_setup_dialog_geometry(VariantSetting_SelectObjectDialogGeometry, this); - g_settings->restore_header_state(VariantSetting_SelectObjectHeaderState, view->header()); + settings_restore_header_state(VariantSetting_SelectObjectHeaderState, view->header()); connect( add_button, &QPushButton::clicked, @@ -144,7 +144,7 @@ SelectObjectDialog::SelectObjectDialog(const QList class_list_arg, cons } SelectObjectDialog::~SelectObjectDialog() { - g_settings->save_header_state(VariantSetting_SelectObjectHeaderState, view->header()); + settings_save_header_state(VariantSetting_SelectObjectHeaderState, view->header()); } QList SelectObjectDialog::get_selected() const { diff --git a/src/admc/settings.cpp b/src/admc/settings.cpp index c978e879..91360e77 100644 --- a/src/admc/settings.cpp +++ b/src/admc/settings.cpp @@ -23,54 +23,46 @@ #include "config.h" #include -#include #include #include #include +#include bool bool_default_value(const BoolSetting setting); QString bool_to_string(const BoolSetting setting); QString variant_to_string(const VariantSetting setting); -Settings::Settings() -: qsettings(ADMC_ORGANIZATION, ADMC_APPLICATION_NAME) { -} +bool settings_get_bool(const BoolSetting setting) { + QSettings settings; -const BoolSettingSignal *Settings::get_bool_signal(const BoolSetting setting) const { - return &bools[setting]; -} - -bool Settings::get_bool(const BoolSetting setting) const { const QString setting_str = bool_to_string(setting); const bool default_value = bool_default_value(setting); - const bool value = qsettings.value(setting_str, default_value).toBool(); + const bool value = settings.value(setting_str, default_value).toBool(); return value; } -void Settings::set_bool(const BoolSetting setting, const bool value) { +void settings_set_bool(const BoolSetting setting, const bool value) { + QSettings settings; + const QString name = bool_to_string(setting); - qsettings.setValue(name, value); + settings.setValue(name, value); } -void Settings::save_geometry(const VariantSetting setting, QWidget *widget) { - const QByteArray geometry = widget->saveGeometry(); - set_variant(setting, geometry); -} - -void Settings::setup_dialog_geometry(const VariantSetting setting, QDialog *dialog) { - restore_geometry(setting, dialog); +void settings_setup_dialog_geometry(const VariantSetting setting, QDialog *dialog) { + settings_restore_geometry(setting, dialog); QDialog::connect( dialog, &QDialog::finished, [=]() { - save_geometry(setting, dialog); + const QByteArray geometry = dialog->saveGeometry(); + settings_set_variant(setting, geometry); }); } -bool Settings::restore_geometry(const VariantSetting setting, QWidget *widget) { - if (contains_variant(setting)) { - const QByteArray geometry = get_variant(setting).toByteArray(); +bool settings_restore_geometry(const VariantSetting setting, QWidget *widget) { + const QByteArray geometry = settings_get_variant(setting).toByteArray(); + if (!geometry.isEmpty()) { widget->restoreGeometry(geometry); return true; @@ -79,14 +71,14 @@ bool Settings::restore_geometry(const VariantSetting setting, QWidget *widget) { } } -void Settings::save_header_state(const VariantSetting setting, QHeaderView *header) { +void settings_save_header_state(const VariantSetting setting, QHeaderView *header) { const QByteArray state = header->saveState(); - set_variant(setting, state); + settings_set_variant(setting, state); } -bool Settings::restore_header_state(const VariantSetting setting, QHeaderView *header) { - if (contains_variant(setting)) { - const QByteArray state = get_variant(setting).toByteArray(); +bool settings_restore_header_state(const VariantSetting setting, QHeaderView *header) { + const QByteArray state = settings_get_variant(setting).toByteArray(); + if (!state.isEmpty()) { header->restoreState(state); return true; @@ -95,69 +87,59 @@ bool Settings::restore_header_state(const VariantSetting setting, QHeaderView *h } } -QVariant Settings::get_variant(const VariantSetting setting) const { +QVariant settings_get_variant(const VariantSetting setting, const QVariant &default_value) { + QSettings settings; const QString name = variant_to_string(setting); - const QVariant value = qsettings.value(name); + const QVariant value = settings.value(name, default_value); return value; } -void Settings::set_variant(const VariantSetting setting, const QVariant &value) { +void settings_set_variant(const VariantSetting setting, const QVariant &value) { + QSettings settings; const QString name = variant_to_string(setting); - qsettings.setValue(name, value); + settings.setValue(name, value); } -bool Settings::contains_variant(const VariantSetting setting) const { - const QString name = variant_to_string(setting); - return qsettings.contains(name); -} - -void Settings::connect_action_to_bool_setting(QAction *action, const BoolSetting setting) { +void settings_connect_action_to_bool_setting(QAction *action, const BoolSetting setting) { action->setCheckable(true); // Init action state to saved value - const bool saved_value = get_bool(setting); + const bool saved_value = settings_get_bool(setting); action->setChecked(saved_value); // Update saved value when action is toggled QObject::connect( action, &QAction::toggled, - [this, setting](bool checked) { - set_bool(setting, checked); - - emit bools[setting].changed(); + [setting](bool checked) { + settings_set_bool(setting, checked); }); } -void Settings::connect_checkbox_to_bool_setting(QCheckBox *check, const BoolSetting setting) { +QAction *settings_make_action(const BoolSetting setting, const QString &text, QObject *parent) { + auto action = new QAction(text, parent); + action->setCheckable(true); + // Init action state to saved value - const bool saved_value = get_bool(setting); - check->setChecked(saved_value); + const bool saved_value = settings_get_bool(setting); + action->setChecked(saved_value); - // Update saved value when checkbox is toggled + return action; +} + +QAction *settings_make_and_connect_action(const BoolSetting setting, const QString &text, QObject *parent) { + auto action = settings_make_action(setting, text, parent); + + // Update saved value when action is toggled QObject::connect( - check, &QCheckBox::stateChanged, - [this, setting, check]() { - const bool checked = check->isChecked(); - set_bool(setting, checked); - - emit bools[setting].changed(); + action, &QAction::toggled, + [setting](bool checked) { + settings_set_bool(setting, checked); }); + + return action; } -void Settings::connect_toggle_widget(QWidget *widget, const BoolSetting setting) { - const BoolSettingSignal *signal = get_bool_signal(setting); - - auto on_changed = [=]() { - const bool visible = get_bool(setting); - widget->setVisible(visible); - }; - - QObject::connect( - signal, &BoolSettingSignal::changed, - on_changed); - on_changed(); -} // NOTE: DON'T define "default:" branch, want to be warned and forced to define a default value for all settings bool bool_default_value(const BoolSetting setting) { @@ -179,14 +161,6 @@ bool bool_default_value(const BoolSetting setting) { case BoolSetting_LogSearches: return false; case BoolSetting_TimestampLog: return true; - case BoolSetting_AttributeFilterUnset: return true; - case BoolSetting_AttributeFilterReadOnly: return true; - case BoolSetting_AttributeFilterMandatory: return true; - case BoolSetting_AttributeFilterOptional: return true; - case BoolSetting_AttributeFilterSystemOnly: return true; - case BoolSetting_AttributeFilterConstructed: return true; - case BoolSetting_AttributeFilterBacklink: return true; - case BoolSetting_COUNT: break; } @@ -194,7 +168,7 @@ bool bool_default_value(const BoolSetting setting) { } #define CASE_ENUM_TO_STRING(ENUM) \ - case ENUM: return #ENUM +case ENUM: return #ENUM // Convert enum to string literal via macro // BoolSetting_Foo => "BoolSetting_Foo" @@ -210,13 +184,6 @@ QString bool_to_string(const BoolSetting setting) { CASE_ENUM_TO_STRING(BoolSetting_LogSearches); CASE_ENUM_TO_STRING(BoolSetting_TimestampLog); CASE_ENUM_TO_STRING(BoolSetting_COUNT); - CASE_ENUM_TO_STRING(BoolSetting_AttributeFilterUnset); - CASE_ENUM_TO_STRING(BoolSetting_AttributeFilterReadOnly); - CASE_ENUM_TO_STRING(BoolSetting_AttributeFilterMandatory); - CASE_ENUM_TO_STRING(BoolSetting_AttributeFilterOptional); - CASE_ENUM_TO_STRING(BoolSetting_AttributeFilterSystemOnly); - CASE_ENUM_TO_STRING(BoolSetting_AttributeFilterConstructed); - CASE_ENUM_TO_STRING(BoolSetting_AttributeFilterBacklink); } return ""; } @@ -230,7 +197,7 @@ QString variant_to_string(const VariantSetting setting) { CASE_ENUM_TO_STRING(VariantSetting_ResultsHeader); CASE_ENUM_TO_STRING(VariantSetting_FindResultsHeader); CASE_ENUM_TO_STRING(VariantSetting_AttributesTabHeaderState); - CASE_ENUM_TO_STRING(VariantSetting_AttributesTabFilter); + CASE_ENUM_TO_STRING(VariantSetting_AttributesTabFilterState); CASE_ENUM_TO_STRING(VariantSetting_QueryFolders); CASE_ENUM_TO_STRING(VariantSetting_QueryItems); CASE_ENUM_TO_STRING(VariantSetting_PropertiesDialogGeometry); diff --git a/src/admc/settings.h b/src/admc/settings.h index 637720d8..4c39c54d 100644 --- a/src/admc/settings.h +++ b/src/admc/settings.h @@ -22,27 +22,19 @@ #define SETTINGS_H /** - * Provides access to settings via enums rather than plain - * strings. Settings are saved to file automatically when - * this object is destructed. Note that you shouldn't save - * settings in destructors that run close to app shutdown - * because they won't be saved to file. Instead use - * QMainWindow::closeEvent(). Settings of boolean type have - * BoolSettingSignal objects which emit changed() signal - * when setting is changed. + * Utility f-ns for saving and loading settings using + * QSettings. */ -#include - -#include +#include class QAction; -class QSettings; class QVariant; class QWidget; -class QCheckBox; class QHeaderView; class QDialog; +class QString; +class QObject; enum VariantSetting { VariantSetting_DC, @@ -52,7 +44,7 @@ enum VariantSetting { VariantSetting_AttributesTabHeaderState, VariantSetting_MainWindowGeometry, VariantSetting_MainWindowState, - VariantSetting_AttributesTabFilter, + VariantSetting_AttributesTabFilterState, VariantSetting_QueryFolders, VariantSetting_QueryItems, VariantSetting_PropertiesDialogGeometry, @@ -86,67 +78,40 @@ enum BoolSetting { BoolSetting_LogSearches, BoolSetting_TimestampLog, - BoolSetting_AttributeFilterUnset, - BoolSetting_AttributeFilterReadOnly, - BoolSetting_AttributeFilterMandatory, - BoolSetting_AttributeFilterOptional, - BoolSetting_AttributeFilterSystemOnly, - BoolSetting_AttributeFilterConstructed, - BoolSetting_AttributeFilterBacklink, - BoolSetting_COUNT, }; -class BoolSettingSignal final : public QObject { - Q_OBJECT -signals: - void changed(); -}; +QVariant settings_get_variant(const VariantSetting setting, const QVariant &default_value = QVariant()); +void settings_set_variant(const VariantSetting setting, const QVariant &value); -class Settings { +// NOTE: returns default value if it's defined in +// settings.cpp +bool settings_get_bool(const BoolSetting setting); +void settings_set_bool(const BoolSetting setting, const bool value); -public: - Settings(); +// Does two things. First it restores previously saved +// geometry, if it exists. Then it connects to dialogs +// finished() signal so that it's geometry is saved when +// dialog is finished. +void settings_setup_dialog_geometry(const VariantSetting setting, QDialog *dialog); - QVariant get_variant(const VariantSetting setting) const; - void set_variant(const VariantSetting setting, const QVariant &value); - bool contains_variant(const VariantSetting setting) const; +// NOTE: If setting is present, restore is performed, +// otherwise f-n does nothing and returns false. You +// should check for the return and perform default +// sizing in the false case. +bool settings_restore_geometry(const VariantSetting setting, QWidget *widget); - const BoolSettingSignal *get_bool_signal(const BoolSetting setting) const; - bool get_bool(const BoolSetting setting) const; - void set_bool(const BoolSetting setting, const bool value); +void settings_save_header_state(const VariantSetting setting, QHeaderView *header); +bool settings_restore_header_state(const VariantSetting setting, QHeaderView *header); - void save_geometry(const VariantSetting setting, QWidget *widget); - - // Does two things. First it restores previously saved - // geometry, if it exists. Then it connects to dialogs - // finished() signal so that it's geometry is saved when - // dialog is finished. - void setup_dialog_geometry(const VariantSetting setting, QDialog *dialog); - - // NOTE: If setting is present, restore is performed, - // otherwise f-n does nothing and returns false. You - // should check for the return and perform default - // sizing in the false case. - bool restore_geometry(const VariantSetting setting, QWidget *widget); - - void save_header_state(const VariantSetting setting, QHeaderView *header); - bool restore_header_state(const VariantSetting setting, QHeaderView *header); - - /** - * Connect action and bool setting so that toggling - * the action updates the setting value - * Action becomes checkable - */ - void connect_action_to_bool_setting(QAction *action, const BoolSetting setting); - - void connect_checkbox_to_bool_setting(QCheckBox *check, const BoolSetting setting); - - void connect_toggle_widget(QWidget *widget, const BoolSetting setting); - -private: - QSettings qsettings; - BoolSettingSignal bools[BoolSetting_COUNT]; -}; +/** + * Make a checkable QAction that is connected to a bool + * setting. Action state will be initialized to the current + * setting value. The "connect" version of the f-n also + * connects the action for you so that when toggling the + * action modifies the setting. + */ +QAction *settings_make_action(const BoolSetting setting, const QString &text, QObject *parent); +QAction *settings_make_and_connect_action(const BoolSetting setting, const QString &text, QObject *parent); #endif /* SETTINGS_H */ diff --git a/src/admc/status.cpp b/src/admc/status.cpp index 8994b227..4c7eddcb 100644 --- a/src/admc/status.cpp +++ b/src/admc/status.cpp @@ -60,7 +60,7 @@ void Status::add_message(const QString &msg, const StatusType &type) { const QString timestamped_msg = QString("%1 %2").arg(timestamp, msg); - const bool timestamps_ON = g_settings->get_bool(BoolSetting_TimestampLog); + const bool timestamps_ON = settings_get_bool(BoolSetting_TimestampLog); const QColor color = [type]() { switch (type) { diff --git a/src/admc/tabs/attributes_tab.cpp b/src/admc/tabs/attributes_tab.cpp index e9a83bb8..9b8dd38e 100644 --- a/src/admc/tabs/attributes_tab.cpp +++ b/src/admc/tabs/attributes_tab.cpp @@ -38,6 +38,7 @@ #include #include #include +#include enum AttributesColumn { AttributesColumn_Name, @@ -57,13 +58,15 @@ AttributesTab::AttributesTab() { {AttributesColumn_Type, tr("Type")}, }); + auto filter_menu = new AttributesFilterMenu(this); + view = new QTreeView(this); view->setEditTriggers(QAbstractItemView::NoEditTriggers); view->setSelectionBehavior(QAbstractItemView::SelectRows); view->setAllColumnsShowFocus(true); view->setSortingEnabled(true); - proxy = new AttributesTabProxy(this); + proxy = new AttributesTabProxy(filter_menu, this); proxy->setSourceModel(model); view->setModel(proxy); @@ -77,27 +80,34 @@ AttributesTab::AttributesTab() { buttons->addStretch(); buttons->addWidget(filter_button); - filter_button->setMenu(new AttributesFilterMenu(this)); + filter_button->setMenu(filter_menu); const auto layout = new QVBoxLayout(); setLayout(layout); layout->addWidget(view); layout->addLayout(buttons); - g_settings->restore_header_state(VariantSetting_AttributesTabHeaderState, view->header()); - enable_widget_on_selection(edit_button, view); + settings_restore_header_state(VariantSetting_AttributesTabHeaderState, view->header()); + + const QHash state = settings_get_variant(VariantSetting_AttributesTabHeaderState).toHash(); + + view->header()->restoreState(state["header"].toByteArray()); + connect( view, &QAbstractItemView::doubleClicked, this, &AttributesTab::edit_attribute); connect( edit_button, &QAbstractButton::clicked, this, &AttributesTab::edit_attribute); + connect( + filter_menu, &AttributesFilterMenu::filter_changed, + proxy, &AttributesTabProxy::invalidate); } AttributesTab::~AttributesTab() { - g_settings->save_header_state(VariantSetting_AttributesTabHeaderState, view->header()); + settings_set_variant(VariantSetting_AttributesTabHeaderState, view->header()->saveState()); } void AttributesTab::edit_attribute() { @@ -208,69 +218,96 @@ void AttributesTab::load_row(const QList &row, const QString &a AttributesFilterMenu::AttributesFilterMenu(QWidget *parent) : QMenu(parent) { - auto add_filter_option = [&](const QString text, const BoolSetting setting) { + const QList state = settings_get_variant(VariantSetting_AttributesTabFilterState).toList(); + + auto add_filter_action = [&](const QString text, const AttributeFilter filter) { QAction *action = addAction(text); action->setText(text); - action->setObjectName(QString::number(setting)); + action->setObjectName(QString::number(filter)); + action->setCheckable(true); - g_settings->connect_action_to_bool_setting(action, setting); + const bool is_checked = [&]() { + if (filter < state.size()) { + return state[filter].toBool(); + } else { + return true; + } + }(); + action->setChecked(is_checked); - action_map.insert(setting, action); + action_map.insert(filter, action); + + connect( + action, &QAction::toggled, + this, &AttributesFilterMenu::filter_changed); }; - add_filter_option(tr("Unset"), BoolSetting_AttributeFilterUnset); - add_filter_option(tr("Read-only"), BoolSetting_AttributeFilterReadOnly); + add_filter_action(tr("Unset"), AttributeFilter_Unset); + add_filter_action(tr("Read-only"), AttributeFilter_ReadOnly); addSeparator(); - add_filter_option(tr("Mandatory"), BoolSetting_AttributeFilterMandatory); - add_filter_option(tr("Optional"), BoolSetting_AttributeFilterOptional); + add_filter_action(tr("Mandatory"), AttributeFilter_Mandatory); + add_filter_action(tr("Optional"), AttributeFilter_Optional); addSeparator(); - add_filter_option(tr("System-only"), BoolSetting_AttributeFilterSystemOnly); - add_filter_option(tr("Constructed"), BoolSetting_AttributeFilterConstructed); - add_filter_option(tr("Backlink"), BoolSetting_AttributeFilterBacklink); + add_filter_action(tr("System-only"), AttributeFilter_SystemOnly); + add_filter_action(tr("Constructed"), AttributeFilter_Constructed); + add_filter_action(tr("Backlink"), AttributeFilter_Backlink); - const BoolSettingSignal *read_only_signal = g_settings->get_bool_signal(BoolSetting_AttributeFilterReadOnly); connect( - read_only_signal, &BoolSettingSignal::changed, + action_map[AttributeFilter_ReadOnly], &QAction::toggled, this, &AttributesFilterMenu::on_read_only_changed); on_read_only_changed(); } -void AttributesFilterMenu::on_read_only_changed() { - const bool read_only_is_enabled = g_settings->get_bool(BoolSetting_AttributeFilterReadOnly); +AttributesFilterMenu::~AttributesFilterMenu() { + const QList state = [&]() { + QList out; - const QList read_only_sub_filters = { - BoolSetting_AttributeFilterSystemOnly, - BoolSetting_AttributeFilterConstructed, - BoolSetting_AttributeFilterBacklink, + for (int fitler_i = 0; fitler_i < AttributeFilter_COUNT; fitler_i++) { + const AttributeFilter filter = (AttributeFilter) fitler_i; + const QAction *action = action_map[filter]; + const QVariant filter_state = QVariant(action->isChecked()); + + out.append(filter_state); + } + + return out; + }(); + + settings_set_variant(VariantSetting_AttributesTabFilterState, state); +} + +void AttributesFilterMenu::on_read_only_changed() { + const bool read_only_is_enabled = action_map[AttributeFilter_ReadOnly]->isChecked(); + + const QList read_only_sub_filters = { + AttributeFilter_SystemOnly, + AttributeFilter_Constructed, + AttributeFilter_Backlink, }; - for (const BoolSetting &setting : read_only_sub_filters) { - action_map[setting]->setEnabled(read_only_is_enabled); - action_map[setting]->setChecked(read_only_is_enabled); + for (const AttributeFilter &filter : read_only_sub_filters) { + action_map[filter]->setEnabled(read_only_is_enabled); + + // Turning off read only turns off the sub read only + // filters. Note that turning ON read only doesn't do + // the opposite. + if (!read_only_is_enabled) { + action_map[filter]->setChecked(false); + } } } -AttributesTabProxy::AttributesTabProxy(QObject *parent) +bool AttributesFilterMenu::filter_is_enabled(const AttributeFilter filter) const { + return action_map[filter]->isChecked(); +} + +AttributesTabProxy::AttributesTabProxy(AttributesFilterMenu *filter_menu_arg, QObject *parent) : QSortFilterProxyModel(parent) { - const QList filter_setting_list = { - BoolSetting_AttributeFilterUnset, - BoolSetting_AttributeFilterReadOnly, - BoolSetting_AttributeFilterMandatory, - BoolSetting_AttributeFilterOptional, - BoolSetting_AttributeFilterSystemOnly, - BoolSetting_AttributeFilterConstructed, - BoolSetting_AttributeFilterBacklink, - }; - for (const BoolSetting &setting : filter_setting_list) { - const BoolSettingSignal *signal = g_settings->get_bool_signal(setting); - connect( - signal, &BoolSettingSignal::changed, - this, &AttributesTabProxy::invalidate); - } + filter_menu = filter_menu_arg; } void AttributesTabProxy::load(const AdObject &object) { @@ -290,36 +327,36 @@ bool AttributesTabProxy::filterAcceptsRow(int source_row, const QModelIndex &sou const bool mandatory = mandatory_attributes.contains(attribute); const bool optional = optional_attributes.contains(attribute); - if (!g_settings->get_bool(BoolSetting_AttributeFilterUnset) && unset) { + if (!filter_menu->filter_is_enabled(AttributeFilter_Unset) && unset) { return false; } - if (!g_settings->get_bool(BoolSetting_AttributeFilterMandatory) && mandatory) { + if (!filter_menu->filter_is_enabled(AttributeFilter_Mandatory) && mandatory) { return false; } - if (!g_settings->get_bool(BoolSetting_AttributeFilterOptional) && optional) { + if (!filter_menu->filter_is_enabled(AttributeFilter_Optional) && optional) { return false; } - if (g_settings->get_bool(BoolSetting_AttributeFilterReadOnly) && system_only) { + if (filter_menu->filter_is_enabled(AttributeFilter_ReadOnly) && system_only) { const bool constructed = g_adconfig->get_attribute_is_constructed(attribute); const bool backlink = g_adconfig->get_attribute_is_backlink(attribute); - if (!g_settings->get_bool(BoolSetting_AttributeFilterSystemOnly) && !constructed && !backlink) { + if (!filter_menu->filter_is_enabled(AttributeFilter_SystemOnly) && !constructed && !backlink) { return false; } - if (!g_settings->get_bool(BoolSetting_AttributeFilterConstructed) && constructed) { + if (!filter_menu->filter_is_enabled(AttributeFilter_Constructed) && constructed) { return false; } - if (!g_settings->get_bool(BoolSetting_AttributeFilterBacklink) && backlink) { + if (!filter_menu->filter_is_enabled(AttributeFilter_Backlink) && backlink) { return false; } } - if (!g_settings->get_bool(BoolSetting_AttributeFilterReadOnly) && system_only) { + if (!filter_menu->filter_is_enabled(AttributeFilter_ReadOnly) && system_only) { return false; } diff --git a/src/admc/tabs/attributes_tab_p.h b/src/admc/tabs/attributes_tab_p.h index af2894e9..94d57b86 100644 --- a/src/admc/tabs/attributes_tab_p.h +++ b/src/admc/tabs/attributes_tab_p.h @@ -28,14 +28,32 @@ #include #include +enum AttributeFilter { + AttributeFilter_Unset, + AttributeFilter_ReadOnly, + AttributeFilter_Mandatory, + AttributeFilter_Optional, + AttributeFilter_SystemOnly, + AttributeFilter_Constructed, + AttributeFilter_Backlink, + + AttributeFilter_COUNT, +}; + class AttributesFilterMenu final : public QMenu { Q_OBJECT public: AttributesFilterMenu(QWidget *parent); + ~AttributesFilterMenu(); + + bool filter_is_enabled(const AttributeFilter filter) const; + +signals: + void filter_changed(); private: - QHash action_map; + QHash action_map; void on_read_only_changed(); }; @@ -43,11 +61,12 @@ private: class AttributesTabProxy final : public QSortFilterProxyModel { public: - AttributesTabProxy(QObject *parent); + AttributesTabProxy(AttributesFilterMenu *filter_menu, QObject *parent); void load(const AdObject &object); private: + AttributesFilterMenu *filter_menu; QSet set_attributes; QSet mandatory_attributes; QSet optional_attributes; diff --git a/src/admc/tabs/gpo_links_tab.cpp b/src/admc/tabs/gpo_links_tab.cpp index 0a8d7c92..27b05329 100644 --- a/src/admc/tabs/gpo_links_tab.cpp +++ b/src/admc/tabs/gpo_links_tab.cpp @@ -62,11 +62,11 @@ GpoLinksTab::GpoLinksTab() { PropertiesDialog::open_when_view_item_activated(view, GpoLinksRole_DN); - g_settings->restore_header_state(VariantSetting_GpoLinksTabHeaderState, view->header()); + settings_restore_header_state(VariantSetting_GpoLinksTabHeaderState, view->header()); } GpoLinksTab::~GpoLinksTab() { - g_settings->save_header_state(VariantSetting_GpoLinksTabHeaderState, view->header()); + settings_save_header_state(VariantSetting_GpoLinksTabHeaderState, view->header()); } void GpoLinksTab::load(AdInterface &ad, const AdObject &object) { diff --git a/src/admc/tabs/group_policy_tab.cpp b/src/admc/tabs/group_policy_tab.cpp index 3ec6176c..7f868cbe 100644 --- a/src/admc/tabs/group_policy_tab.cpp +++ b/src/admc/tabs/group_policy_tab.cpp @@ -94,7 +94,7 @@ GroupPolicyTab::GroupPolicyTab() { layout->addLayout(button_layout); layout->addLayout(edits_layout); - g_settings->restore_header_state(VariantSetting_GroupPolicyTabHeaderState, view->header()); + settings_restore_header_state(VariantSetting_GroupPolicyTabHeaderState, view->header()); enable_widget_on_selection(remove_button, view); @@ -113,7 +113,7 @@ GroupPolicyTab::GroupPolicyTab() { } GroupPolicyTab::~GroupPolicyTab() { - g_settings->save_header_state(VariantSetting_GroupPolicyTabHeaderState, view->header()); + settings_save_header_state(VariantSetting_GroupPolicyTabHeaderState, view->header()); } void GroupPolicyTab::load(AdInterface &ad, const AdObject &object) { diff --git a/src/admc/tabs/membership_tab.cpp b/src/admc/tabs/membership_tab.cpp index 3613a8e5..e9ad2ed0 100644 --- a/src/admc/tabs/membership_tab.cpp +++ b/src/admc/tabs/membership_tab.cpp @@ -105,7 +105,7 @@ MembershipTab::MembershipTab(const MembershipTabType type_arg) { layout->addWidget(primary_group_label); layout->addLayout(button_layout); - g_settings->restore_header_state(VariantSetting_MembershipTabHeaderState, view->header()); + settings_restore_header_state(VariantSetting_MembershipTabHeaderState, view->header()); enable_widget_on_selection(remove_button, view); enable_widget_on_selection(properties_button, view); @@ -133,7 +133,7 @@ MembershipTab::MembershipTab(const MembershipTabType type_arg) { } MembershipTab::~MembershipTab() { - g_settings->save_header_state(VariantSetting_MembershipTabHeaderState, view->header()); + settings_save_header_state(VariantSetting_MembershipTabHeaderState, view->header()); } void MembershipTab::load(AdInterface &ad, const AdObject &object) { diff --git a/src/admc/tabs/organization_tab.cpp b/src/admc/tabs/organization_tab.cpp index b5631082..1d1a0ec7 100644 --- a/src/admc/tabs/organization_tab.cpp +++ b/src/admc/tabs/organization_tab.cpp @@ -78,11 +78,11 @@ OrganizationTab::OrganizationTab() { layout->addRow(reports_label); layout->addRow(reports_view); - g_settings->restore_header_state(VariantSetting_OrganizationTabHeaderState, reports_view->header()); + settings_restore_header_state(VariantSetting_OrganizationTabHeaderState, reports_view->header()); } OrganizationTab::~OrganizationTab() { - g_settings->save_header_state(VariantSetting_OrganizationTabHeaderState, reports_view->header()); + settings_save_header_state(VariantSetting_OrganizationTabHeaderState, reports_view->header()); } void OrganizationTab::load(AdInterface &ad, const AdObject &object) { diff --git a/src/admc/tabs/security_tab.cpp b/src/admc/tabs/security_tab.cpp index 50153645..a09cb99f 100644 --- a/src/admc/tabs/security_tab.cpp +++ b/src/admc/tabs/security_tab.cpp @@ -154,7 +154,7 @@ SecurityTab::SecurityTab() { layout->addWidget(trustee_label); layout->addWidget(ace_view); - g_settings->restore_header_state(VariantSetting_SecurityTabHeaderState, ace_view->header()); + settings_restore_header_state(VariantSetting_SecurityTabHeaderState, ace_view->header()); connect( trustee_view->selectionModel(), &QItemSelectionModel::currentChanged, @@ -174,7 +174,7 @@ SecurityTab::SecurityTab() { } SecurityTab::~SecurityTab() { - g_settings->save_header_state(VariantSetting_SecurityTabHeaderState, ace_view->header()); + settings_save_header_state(VariantSetting_SecurityTabHeaderState, ace_view->header()); } void SecurityTab::load(AdInterface &ad, const AdObject &object) { diff --git a/src/admc/utils.cpp b/src/admc/utils.cpp index 406f5543..ef8df9d0 100644 --- a/src/admc/utils.cpp +++ b/src/admc/utils.cpp @@ -78,22 +78,6 @@ void set_horizontal_header_labels_from_map(QStandardItemModel *model, const QMap } } -void show_only_in_dev_mode(QWidget *widget) { - const BoolSettingSignal *dev_mode_signal = g_settings->get_bool_signal(BoolSetting_DevMode); - - const auto do_it = [widget]() { - const bool dev_mode = g_settings->get_bool(BoolSetting_DevMode); - widget->setVisible(dev_mode); - }; - do_it(); - - QObject::connect( - dev_mode_signal, &BoolSettingSignal::changed, - [do_it]() { - do_it(); - }); -} - void set_line_edit_to_numbers_only(QLineEdit *edit) { edit->setValidator(new QRegExpValidator(QRegExp("[0-9]*"), edit)); } @@ -121,7 +105,7 @@ void hide_busy_indicator() { } bool confirmation_dialog(const QString &text, QWidget *parent) { - const bool confirm_actions = g_settings->get_bool(BoolSetting_ConfirmActions); + const bool confirm_actions = settings_get_bool(BoolSetting_ConfirmActions); if (!confirm_actions) { return true; } @@ -225,7 +209,7 @@ QList persistent_index_list(const QList &ind // Hide advanced view only" objects if advanced view setting // is off void advanced_features_filter(QString &filter) { - const bool advanced_features_OFF = !g_settings->get_bool(BoolSetting_AdvancedFeatures); + const bool advanced_features_OFF = !settings_get_bool(BoolSetting_AdvancedFeatures); if (advanced_features_OFF) { const QString advanced_features = filter_CONDITION(Condition_NotEquals, ATTRIBUTE_SHOW_IN_ADVANCED_VIEW_ONLY, LDAP_BOOL_TRUE); filter = filter_AND({filter, advanced_features}); @@ -235,7 +219,7 @@ void advanced_features_filter(QString &filter) { // OR filter with some dev mode object classes, so that they // show up no matter what when dev mode is on void dev_mode_filter(QString &filter) { - const bool dev_mode = g_settings->get_bool(BoolSetting_DevMode); + const bool dev_mode = settings_get_bool(BoolSetting_DevMode); if (!dev_mode) { return; } @@ -259,7 +243,7 @@ void dev_mode_filter(QString &filter) { // they don't show up in regular searches. Have to use // search_object() and manually add them to search results. void dev_mode_search_results(QHash &results, AdInterface &ad, const QString &base) { - const bool dev_mode = g_settings->get_bool(BoolSetting_DevMode); + const bool dev_mode = settings_get_bool(BoolSetting_DevMode); if (!dev_mode) { return; } diff --git a/src/admc/utils.h b/src/admc/utils.h index 47c1faf3..65878a8d 100644 --- a/src/admc/utils.h +++ b/src/admc/utils.h @@ -59,8 +59,6 @@ void exec_menu_from_view(QMenu *menu, const QAbstractItemView *view, const QPoin // Columns not in the map get empty labels void set_horizontal_header_labels_from_map(QStandardItemModel *model, const QMap &labels_map); -void show_only_in_dev_mode(QWidget *widget); - // Prohibits leading zeroes void set_line_edit_to_numbers_only(QLineEdit *edit); diff --git a/tests/admc_test_attributes_tab.cpp b/tests/admc_test_attributes_tab.cpp index 322fb5c0..139c1651 100644 --- a/tests/admc_test_attributes_tab.cpp +++ b/tests/admc_test_attributes_tab.cpp @@ -31,16 +31,18 @@ #include #include +Q_DECLARE_METATYPE(AttributeFilter) + // NOTE: can't be set because order is important. Read only // has to be set first to enable other filters. -const QList all_filters = { - BoolSetting_AttributeFilterUnset, - BoolSetting_AttributeFilterReadOnly, - BoolSetting_AttributeFilterMandatory, - BoolSetting_AttributeFilterOptional, - BoolSetting_AttributeFilterSystemOnly, - BoolSetting_AttributeFilterConstructed, - BoolSetting_AttributeFilterBacklink, +const QList all_filters = { + AttributeFilter_Unset, + AttributeFilter_ReadOnly, + AttributeFilter_Mandatory, + AttributeFilter_Optional, + AttributeFilter_SystemOnly, + AttributeFilter_Constructed, + AttributeFilter_Backlink, }; void ADMCTestAttributesTab::init() { @@ -103,46 +105,55 @@ void ADMCTestAttributesTab::load() { check_value("distinguishedName", dn); } -// Test filters by checking that affected attributes are -// visible/hidden when their filters are checked/unchecked -void ADMCTestAttributesTab::filter() { - auto test_filter = [&](const BoolSetting filter, const QString &attribute) { - auto check_filtering = [&](const bool should_be_visible) { - const QList item_list = model->findItems(attribute); - QVERIFY2((item_list.size() == 1), qPrintable(QString("Failed to find attribute %1)").arg(attribute))); +void ADMCTestAttributesTab::filter_data() { + QTest::addColumn("filter"); + QTest::addColumn("attribute"); - QStandardItem *item = item_list[0]; - const QModelIndex index = item->index(); - const QModelIndex proxy_index = proxy->mapFromSource(index); - const bool is_visible = proxy_index.isValid(); - - const bool correct_filtering = (is_visible == should_be_visible); - QVERIFY2(correct_filtering, qPrintable(QString("filter = %1, attribute = %2, is_visible = %3, should_be_visible = %4").arg(filter).arg(attribute).arg(is_visible).arg(should_be_visible))); - }; - - set_filter({filter}, true); - check_filtering(true); - set_filter({filter}, false); - check_filtering(false); - set_filter({filter}, true); - }; - - set_filter(all_filters, true); - - test_filter(BoolSetting_AttributeFilterUnset, ATTRIBUTE_HOME_PHONE); - test_filter(BoolSetting_AttributeFilterReadOnly, ATTRIBUTE_OBJECT_GUID); - test_filter(BoolSetting_AttributeFilterSystemOnly, ATTRIBUTE_WHEN_CREATED); - test_filter(BoolSetting_AttributeFilterConstructed, "allowedAttributes"); - test_filter(BoolSetting_AttributeFilterBacklink, ATTRIBUTE_MEMBER_OF); - test_filter(BoolSetting_AttributeFilterMandatory, "instanceType"); - test_filter(BoolSetting_AttributeFilterOptional, ATTRIBUTE_COUNTRY_CODE); + QTest::newRow("unset") << AttributeFilter_Unset << ATTRIBUTE_HOME_PHONE; + QTest::newRow("read only") << AttributeFilter_ReadOnly << ATTRIBUTE_OBJECT_GUID; + QTest::newRow("system only") << AttributeFilter_SystemOnly << ATTRIBUTE_WHEN_CREATED; + QTest::newRow("constructed") << AttributeFilter_Constructed << "allowedAttributes"; + QTest::newRow("backlink") << AttributeFilter_Backlink << ATTRIBUTE_MEMBER_OF; + QTest::newRow("mandatory") << AttributeFilter_Mandatory << "instanceType"; + QTest::newRow("optional") << AttributeFilter_Optional << ATTRIBUTE_COUNTRY_CODE; // NOTE: read only also needs to affect these read only // attributes - test_filter(BoolSetting_AttributeFilterReadOnly, "allowedAttributes"); - test_filter(BoolSetting_AttributeFilterReadOnly, ATTRIBUTE_WHEN_CREATED); - test_filter(BoolSetting_AttributeFilterReadOnly, ATTRIBUTE_MEMBER_OF); + QTest::newRow("read only allowed") << AttributeFilter_ReadOnly << "allowedAttributes"; + QTest::newRow("read only when created") << AttributeFilter_ReadOnly << ATTRIBUTE_WHEN_CREATED; + QTest::newRow("read only member of") << AttributeFilter_ReadOnly << ATTRIBUTE_MEMBER_OF; +} +// Test filters by checking that affected attributes are +// visible/hidden when their filters are checked/unchecked +void ADMCTestAttributesTab::filter() { + QFETCH(AttributeFilter, filter); + QFETCH(QString, attribute); + + auto check_filtering = [&](const bool should_be_visible) { + const QList item_list = model->findItems(attribute); + QVERIFY2((item_list.size() == 1), qPrintable(QString("Failed to find attribute %1)").arg(attribute))); + + QStandardItem *item = item_list[0]; + const QModelIndex index = item->index(); + const QModelIndex proxy_index = proxy->mapFromSource(index); + const bool is_visible = proxy_index.isValid(); + + const bool correct_filtering = (is_visible == should_be_visible); + QVERIFY2(correct_filtering, qPrintable(QString("filter = %1, attribute = %2, is_visible = %3, should_be_visible = %4").arg(filter).arg(attribute).arg(is_visible).arg(should_be_visible))); + }; + + // Disable(check) all filters (to filter nothing) and + // check that attribute is shown + set_filter(all_filters, true); + check_filtering(true); + + // Enable(uncheck) filter and check that attribute is + // hidden + set_filter({filter}, false); + check_filtering(false); + + // Reset after test is done set_filter(all_filters, true); } @@ -180,8 +191,8 @@ void ADMCTestAttributesTab::apply() { QVERIFY(description_value == correct_value); } -void ADMCTestAttributesTab::set_filter(const QList &filter_list, const bool state) { - for (const BoolSetting &filter : filter_list) { +void ADMCTestAttributesTab::set_filter(const QList &filter_list, const bool state) { + for (const AttributeFilter &filter : filter_list) { QAction *action = filter_menu->findChild(QString::number(filter)); QVERIFY(action != nullptr); action->setChecked(state); diff --git a/tests/admc_test_attributes_tab.h b/tests/admc_test_attributes_tab.h index 00a19b04..5de195e3 100644 --- a/tests/admc_test_attributes_tab.h +++ b/tests/admc_test_attributes_tab.h @@ -41,6 +41,7 @@ private slots: void apply(); void load(); + void filter_data(); void filter(); private: @@ -53,7 +54,7 @@ private: QPushButton *edit_button; QString dn; - void set_filter(const QList &filter_list, const bool state); + void set_filter(const QList &filter_list, const bool state); }; #endif /* ADMC_TEST_ATTRIBUTES_TAB_H */