mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-06 01:11:18 -05:00
45b12e6028
Re-enabling the WSJT-X i18n facilities. This allows translation files to be created for languages that are automatically used to lookup translatable strings. To enable a new language the language name must be added to the CMakeLists.txt LANGUAGES list variable in BCP47 format (i.e. en_US, en_GB, pt_PT, ...). Do one build with the CMake option UPDATE_TRANSLATIONS enabled (do not leave it enabled as there is a danger of loosing existing translated texts), that will create a fresh translations/wsjtx_<lang>.ts file which should be immediately checked in with the CMakeLists.txt change. The .ts should then be updated by the translator using the Qt Linguist tool to add translations. Check in the updated .ts file to complete the initial translation process for that language. To aid translators their WIP .ts file may be tested by releasing (using the lrelease tool or from the Linguist menu) a .qm file and placing that .qm file in the current directory before starting WSJT-X. The translations will be used if the system locale matches the file name. If the system locale does not match the file name; the language may be overridden by setting the LANG environment variable. For example if a wsjtx_pt_PT.qm file is in the current directory WSJT-X will use it for translation lookups, regardless of the current system locale setting, if the LANG variable is set to pt_PT or pt-PT. On MS Windows from a command prompt: set LANG=pt_PT C:\WSJT\wsjtx\bin\wsjtx elsewhere: LANG=pt_PT wsjtx
796 lines
27 KiB
C++
796 lines
27 KiB
C++
#include "MultiSettings.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <QObject>
|
|
#include <QSettings>
|
|
#include <QString>
|
|
#include <QStringList>
|
|
#include <QDir>
|
|
#include <QFont>
|
|
#include <QApplication>
|
|
#include <QStandardPaths>
|
|
#include <QMainWindow>
|
|
#include <QMenu>
|
|
#include <QAction>
|
|
#include <QActionGroup>
|
|
#include <QDialog>
|
|
#include <QLineEdit>
|
|
#include <QRegularExpression>
|
|
#include <QRegularExpressionValidator>
|
|
#include <QFormLayout>
|
|
#include <QVBoxLayout>
|
|
#include <QDialogButtonBox>
|
|
#include <QPushButton>
|
|
#include <QComboBox>
|
|
#include <QLabel>
|
|
#include <QList>
|
|
#include <QMetaObject>
|
|
|
|
#include "SettingsGroup.hpp"
|
|
#include "qt_helpers.hpp"
|
|
#include "SettingsGroup.hpp"
|
|
#include "widgets/MessageBox.hpp"
|
|
|
|
#include "pimpl_impl.hpp"
|
|
|
|
namespace
|
|
{
|
|
char const * default_string = QT_TRANSLATE_NOOP ("MultiSettings", "Default");
|
|
char const * multi_settings_root_group = "MultiSettings";
|
|
char const * multi_settings_current_group_key = "CurrentMultiSettingsConfiguration";
|
|
char const * multi_settings_current_name_key = "CurrentName";
|
|
char const * multi_settings_place_holder_key = "MultiSettingsPlaceHolder";
|
|
|
|
QString unescape_ampersands (QString s)
|
|
{
|
|
return s.replace ("&&", "&");
|
|
}
|
|
|
|
// calculate a useable and unique settings file path
|
|
QString settings_path ()
|
|
{
|
|
auto const& config_directory = QStandardPaths::writableLocation (QStandardPaths::ConfigLocation);
|
|
QDir config_path {config_directory}; // will be "." if config_directory is empty
|
|
if (!config_path.mkpath ("."))
|
|
{
|
|
throw std::runtime_error {"Cannot find a usable configuration path \"" + config_path.path ().toStdString () + '"'};
|
|
}
|
|
return config_path.absoluteFilePath (QApplication::applicationName () + ".ini");
|
|
}
|
|
|
|
//
|
|
// Dialog to get a valid new configuration name
|
|
//
|
|
class NameDialog final
|
|
: public QDialog
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit NameDialog (QString const& current_name,
|
|
QStringList const& current_names,
|
|
QWidget * parent = nullptr)
|
|
: QDialog {parent}
|
|
{
|
|
setWindowTitle (tr ("New Configuration Name"));
|
|
|
|
auto form_layout = new QFormLayout ();
|
|
form_layout->addRow (tr ("Old name:"), &old_name_label_);
|
|
old_name_label_.setText (current_name);
|
|
form_layout->addRow (tr ("&New name:"), &name_line_edit_);
|
|
|
|
auto main_layout = new QVBoxLayout (this);
|
|
main_layout->addLayout (form_layout);
|
|
|
|
auto button_box = new QDialogButtonBox {QDialogButtonBox::Ok | QDialogButtonBox::Cancel};
|
|
button_box->button (QDialogButtonBox::Ok)->setEnabled (false);
|
|
main_layout->addWidget (button_box);
|
|
|
|
auto name_validator = new QRegularExpressionValidator {QRegularExpression {R"([^/\\]+)"}, this};
|
|
name_line_edit_.setValidator (name_validator);
|
|
|
|
connect (&name_line_edit_, &QLineEdit::textChanged, [current_names, button_box] (QString const& name) {
|
|
bool valid {!current_names.contains (name.trimmed ())};
|
|
button_box->button (QDialogButtonBox::Ok)->setEnabled (valid);
|
|
});
|
|
connect (button_box, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
|
connect (button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
|
}
|
|
|
|
QString new_name () const
|
|
{
|
|
return name_line_edit_.text ().trimmed ();
|
|
}
|
|
|
|
private:
|
|
QLabel old_name_label_;
|
|
QLineEdit name_line_edit_;
|
|
};
|
|
|
|
//
|
|
// Dialog to get a valid new existing name
|
|
//
|
|
class ExistingNameDialog final
|
|
: public QDialog
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit ExistingNameDialog (QStringList const& current_names, QWidget * parent = nullptr)
|
|
: QDialog {parent}
|
|
{
|
|
setWindowTitle (tr ("Configuration to Clone From"));
|
|
|
|
name_combo_box_.addItems (current_names);
|
|
|
|
auto form_layout = new QFormLayout ();
|
|
form_layout->addRow (tr ("&Source Configuration Name:"), &name_combo_box_);
|
|
|
|
auto main_layout = new QVBoxLayout (this);
|
|
main_layout->addLayout (form_layout);
|
|
|
|
auto button_box = new QDialogButtonBox {QDialogButtonBox::Ok | QDialogButtonBox::Cancel};
|
|
main_layout->addWidget (button_box);
|
|
|
|
connect (button_box, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
|
connect (button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
|
}
|
|
|
|
QString name () const
|
|
{
|
|
return name_combo_box_.currentText ();
|
|
}
|
|
|
|
private:
|
|
QComboBox name_combo_box_;
|
|
};
|
|
}
|
|
|
|
class MultiSettings::impl final
|
|
: public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit impl (MultiSettings const * parent, QString const& config_name);
|
|
bool reposition ();
|
|
void create_menu_actions (QMainWindow * main_window, QMenu * menu);
|
|
bool exit ();
|
|
|
|
QSettings settings_;
|
|
|
|
private:
|
|
using Dictionary = QMap<QString, QVariant>;
|
|
|
|
// create a configuration maintenance sub menu
|
|
QMenu * create_sub_menu (QMainWindow * main_window,
|
|
QMenu * parent,
|
|
QString const& menu_title,
|
|
QActionGroup * = nullptr);
|
|
|
|
// extract all settings from the current QSettings group
|
|
Dictionary get_settings () const;
|
|
|
|
// write the settings values from the dictionary to the current group
|
|
void load_from (Dictionary const&, bool add_placeholder = true);
|
|
|
|
// switch to this configuration
|
|
void select_configuration (QMainWindow *, QMenu const *);
|
|
|
|
// clone this configuration
|
|
void clone_configuration (QMainWindow * main_window, QMenu *, QMenu const *);
|
|
|
|
// update this configuration from another
|
|
void clone_into_configuration (QMainWindow *, QMenu const *);
|
|
|
|
// reset configuration to default values
|
|
void reset_configuration (QMainWindow *, QMenu const *);
|
|
|
|
// change configuration name
|
|
void rename_configuration (QMainWindow *, QMenu *);
|
|
|
|
// remove a configuration
|
|
void delete_configuration (QMainWindow *, QMenu *);
|
|
|
|
MultiSettings const * parent_; // required for emitting signals
|
|
bool name_change_emit_pending_; // delayed until menu built
|
|
|
|
QFont original_font_;
|
|
QString current_;
|
|
|
|
// action to take on restart
|
|
enum class RepositionType {unchanged, replace, save_and_replace} reposition_type_;
|
|
Dictionary new_settings_;
|
|
bool exit_flag_; // false means loop around with new
|
|
// configuration
|
|
QActionGroup * configurations_group_;
|
|
};
|
|
|
|
#include "MultiSettings.moc"
|
|
#include "moc_MultiSettings.cpp"
|
|
|
|
MultiSettings::MultiSettings (QString const& config_name)
|
|
: m_ {this, config_name}
|
|
{
|
|
}
|
|
|
|
MultiSettings::~MultiSettings ()
|
|
{
|
|
}
|
|
|
|
QSettings * MultiSettings::settings ()
|
|
{
|
|
return &m_->settings_;
|
|
}
|
|
|
|
QVariant MultiSettings::common_value (QString const& key, QVariant const& default_value) const
|
|
{
|
|
QVariant value;
|
|
QSettings * mutable_settings {const_cast<QSettings *> (&m_->settings_)};
|
|
auto const& current_group = mutable_settings->group ();
|
|
if (current_group.size ()) mutable_settings->endGroup ();
|
|
{
|
|
SettingsGroup alternatives {mutable_settings, multi_settings_root_group};
|
|
value = mutable_settings->value (key, default_value);
|
|
}
|
|
if (current_group.size ()) mutable_settings->beginGroup (current_group);
|
|
return value;
|
|
}
|
|
|
|
void MultiSettings::set_common_value (QString const& key, QVariant const& value)
|
|
{
|
|
auto const& current_group = m_->settings_.group ();
|
|
if (current_group.size ()) m_->settings_.endGroup ();
|
|
{
|
|
SettingsGroup alternatives {&m_->settings_, multi_settings_root_group};
|
|
m_->settings_.setValue (key, value);
|
|
}
|
|
if (current_group.size ()) m_->settings_.beginGroup (current_group);
|
|
}
|
|
|
|
void MultiSettings::remove_common_value (QString const& key)
|
|
{
|
|
if (!key.size ()) return; // we don't allow global delete as it
|
|
// would break this classes data model
|
|
auto const& current_group = m_->settings_.group ();
|
|
if (current_group.size ()) m_->settings_.endGroup ();
|
|
{
|
|
SettingsGroup alternatives {&m_->settings_, multi_settings_root_group};
|
|
m_->settings_.remove (key);
|
|
}
|
|
if (current_group.size ()) m_->settings_.beginGroup (current_group);
|
|
}
|
|
|
|
void MultiSettings::create_menu_actions (QMainWindow * main_window, QMenu * menu)
|
|
{
|
|
m_->create_menu_actions (main_window, menu);
|
|
}
|
|
|
|
bool MultiSettings::exit ()
|
|
{
|
|
return m_->exit ();
|
|
}
|
|
|
|
MultiSettings::impl::impl (MultiSettings const * parent, QString const& config_name)
|
|
: settings_ {settings_path (), QSettings::IniFormat}
|
|
, parent_ {parent}
|
|
, name_change_emit_pending_ {true}
|
|
, reposition_type_ {RepositionType::unchanged}
|
|
, exit_flag_ {true}
|
|
, configurations_group_ {new QActionGroup {this}}
|
|
{
|
|
if (!settings_.isWritable ())
|
|
{
|
|
throw std::runtime_error {QString {"Cannot access \"%1\" for writing"}
|
|
.arg (settings_.fileName ()).toStdString ()};
|
|
}
|
|
|
|
// deal with transient, now defunct, settings key
|
|
if (settings_.contains (multi_settings_current_group_key))
|
|
{
|
|
current_ = settings_.value (multi_settings_current_group_key).toString ();
|
|
settings_.remove (multi_settings_current_group_key);
|
|
if (current_.size ())
|
|
{
|
|
{
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
{
|
|
SettingsGroup source_group {&settings_, current_};
|
|
new_settings_ = get_settings ();
|
|
}
|
|
settings_.setValue (multi_settings_current_name_key, tr (default_string));
|
|
}
|
|
reposition_type_ = RepositionType::save_and_replace;
|
|
reposition ();
|
|
}
|
|
else
|
|
{
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
settings_.setValue (multi_settings_current_name_key, tr (default_string));
|
|
}
|
|
}
|
|
|
|
// bootstrap
|
|
QStringList available_configurations;
|
|
{
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
available_configurations = settings_.childGroups ();
|
|
// use last selected configuration
|
|
current_ = settings_.value (multi_settings_current_name_key).toString ();
|
|
if (!current_.size ())
|
|
{
|
|
// no configurations so use default name
|
|
current_ = tr (default_string);
|
|
settings_.setValue (multi_settings_current_name_key, current_);
|
|
}
|
|
}
|
|
|
|
if (config_name.size () && available_configurations.contains (config_name) && config_name != current_)
|
|
{
|
|
// switch to specified configuration
|
|
{
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
// save the target settings
|
|
SettingsGroup target_group {&settings_, config_name};
|
|
new_settings_ = get_settings ();
|
|
}
|
|
current_ = config_name;
|
|
reposition_type_ = RepositionType::save_and_replace;
|
|
reposition ();
|
|
}
|
|
settings_.sync ();
|
|
}
|
|
|
|
// do actions that can only be done once all the windows are closed
|
|
bool MultiSettings::impl::reposition ()
|
|
{
|
|
auto const& current_group = settings_.group ();
|
|
if (current_group.size ()) settings_.endGroup ();
|
|
switch (reposition_type_)
|
|
{
|
|
case RepositionType::save_and_replace:
|
|
{
|
|
// save the current settings with the other alternatives
|
|
Dictionary saved_settings {get_settings ()};
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
// get the current configuration name
|
|
auto const& previous_group_name = settings_.value (multi_settings_current_name_key, tr (default_string)).toString ();
|
|
SettingsGroup save_group {&settings_, previous_group_name};
|
|
load_from (saved_settings);
|
|
}
|
|
// fall through
|
|
case RepositionType::replace:
|
|
// and purge current settings
|
|
for (auto const& key: settings_.allKeys ())
|
|
{
|
|
if (!key.contains (multi_settings_root_group))
|
|
{
|
|
settings_.remove (key);
|
|
}
|
|
}
|
|
// insert the new settings
|
|
load_from (new_settings_, false);
|
|
if (!new_settings_.size ())
|
|
{
|
|
// if we are clearing the current settings then we must
|
|
// reset the application font and the font in the
|
|
// application style sheet, this is necessary since the
|
|
// application instance is not recreated
|
|
qApp->setFont (original_font_);
|
|
qApp->setStyleSheet (qApp->styleSheet () + "* {" + font_as_stylesheet (original_font_) + '}');
|
|
}
|
|
// now we have set up the new current we can safely purge it
|
|
// from the alternatives
|
|
{
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
{
|
|
SettingsGroup purge_group {&settings_, current_};
|
|
settings_.remove (QString {}); // purge entire group
|
|
}
|
|
// switch to the specified configuration name
|
|
settings_.setValue (multi_settings_current_name_key, current_);
|
|
}
|
|
settings_.sync ();
|
|
// fall through
|
|
case RepositionType::unchanged:
|
|
new_settings_.clear ();
|
|
break;
|
|
}
|
|
if (current_group.size ()) settings_.beginGroup (current_group);
|
|
|
|
reposition_type_ = RepositionType::unchanged; // reset
|
|
bool exit {exit_flag_};
|
|
exit_flag_ = true; // reset exit flag so normal exit works
|
|
|
|
return exit;
|
|
}
|
|
|
|
// populate a pop up menu with the configurations sub-menus for
|
|
// maintenance including select, clone, clone from, delete, rename
|
|
// and, reset
|
|
void MultiSettings::impl::create_menu_actions (QMainWindow * main_window, QMenu * menu)
|
|
{
|
|
auto const& current_group = settings_.group ();
|
|
if (current_group.size ()) settings_.endGroup ();
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
// get the current configuration name
|
|
auto const& current_configuration_name = settings_.value (multi_settings_current_name_key, tr (default_string)).toString ();
|
|
// add the default configuration sub menu
|
|
QMenu * default_menu = create_sub_menu (main_window, menu, current_configuration_name, configurations_group_);
|
|
// and set as the current configuration
|
|
default_menu->menuAction ()->setChecked (true);
|
|
|
|
// get the existing alternatives
|
|
auto const& available_configurations = settings_.childGroups ();
|
|
|
|
// add all the other configurations
|
|
for (auto const& configuration_name: available_configurations)
|
|
{
|
|
create_sub_menu (main_window, menu, configuration_name, configurations_group_);
|
|
}
|
|
|
|
if (current_group.size ()) settings_.beginGroup (current_group);
|
|
|
|
if (name_change_emit_pending_)
|
|
{
|
|
Q_EMIT parent_->configurationNameChanged (unescape_ampersands (current_));
|
|
name_change_emit_pending_ = false;
|
|
}
|
|
}
|
|
|
|
// call this at the end of the main program loop to determine if the
|
|
// main window really wants to quit or to run again with a new configuration
|
|
bool MultiSettings::impl::exit ()
|
|
{
|
|
// ensure that configuration name changed signal gets fired on restart
|
|
name_change_emit_pending_ = true;
|
|
|
|
// do any configuration swap required and return exit flag
|
|
return reposition ();
|
|
}
|
|
|
|
QMenu * MultiSettings::impl::create_sub_menu (QMainWindow * main_window,
|
|
QMenu * parent_menu,
|
|
QString const& menu_title,
|
|
QActionGroup * action_group)
|
|
{
|
|
auto sub_menu = parent_menu->addMenu (menu_title);
|
|
if (action_group) action_group->addAction (sub_menu->menuAction ());
|
|
sub_menu->menuAction ()->setCheckable (true);
|
|
|
|
// populate sub-menu actions before showing
|
|
connect (sub_menu, &QMenu::aboutToShow, [this, main_window, parent_menu, sub_menu] () {
|
|
// depopulate before populating and showing because on Mac OS X
|
|
// there is an issue with depopulating in QMenu::aboutToHide()
|
|
// with connections being disconnected before they are actioned
|
|
while (!sub_menu->actions ().isEmpty ())
|
|
{
|
|
sub_menu->removeAction (sub_menu->actions ().last ());
|
|
}
|
|
|
|
bool is_current {sub_menu->menuAction ()->text () == current_};
|
|
if (!is_current)
|
|
{
|
|
auto select_action = new QAction {tr ("&Switch To"), this};
|
|
sub_menu->addAction (select_action);
|
|
connect (select_action, &QAction::triggered, [this, main_window, sub_menu] (bool) {
|
|
select_configuration (main_window, sub_menu);
|
|
});
|
|
sub_menu->addSeparator ();
|
|
}
|
|
|
|
auto clone_action = new QAction {tr ("&Clone"), this};
|
|
sub_menu->addAction (clone_action);
|
|
connect (clone_action, &QAction::triggered, [this, main_window, parent_menu, sub_menu] (bool) {
|
|
clone_configuration (main_window, parent_menu, sub_menu);
|
|
});
|
|
|
|
auto const& current_group = settings_.group ();
|
|
if (current_group.size ()) settings_.endGroup ();
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
if (settings_.childGroups ().size ())
|
|
{
|
|
auto clone_into_action = new QAction {tr ("Clone &Into ..."), this};
|
|
sub_menu->addAction (clone_into_action);
|
|
connect (clone_into_action, &QAction::triggered, [this, main_window, sub_menu] (bool) {
|
|
clone_into_configuration (main_window, sub_menu);
|
|
});
|
|
}
|
|
if (current_group.size ()) settings_.beginGroup (current_group);
|
|
auto reset_action = new QAction {tr ("R&eset"), this};
|
|
sub_menu->addAction (reset_action);
|
|
connect (reset_action, &QAction::triggered, [this, main_window, sub_menu] (bool) {
|
|
reset_configuration (main_window, sub_menu);
|
|
});
|
|
|
|
auto rename_action = new QAction {tr ("&Rename ..."), this};
|
|
sub_menu->addAction (rename_action);
|
|
connect (rename_action, &QAction::triggered, [this, main_window, sub_menu] (bool) {
|
|
rename_configuration (main_window, sub_menu);
|
|
});
|
|
|
|
if (!is_current)
|
|
{
|
|
auto delete_action = new QAction {tr ("&Delete"), this};
|
|
sub_menu->addAction (delete_action);
|
|
connect (delete_action, &QAction::triggered, [this, main_window, sub_menu] (bool) {
|
|
delete_configuration (main_window, sub_menu);
|
|
});
|
|
}
|
|
});
|
|
|
|
return sub_menu;
|
|
}
|
|
|
|
auto MultiSettings::impl::get_settings () const -> Dictionary
|
|
{
|
|
Dictionary settings;
|
|
for (auto const& key: settings_.allKeys ())
|
|
{
|
|
// filter out multi settings group and empty settings
|
|
// placeholder
|
|
if (!key.contains (multi_settings_root_group)
|
|
&& !key.contains (multi_settings_place_holder_key))
|
|
{
|
|
settings[key] = settings_.value (key);
|
|
}
|
|
}
|
|
return settings;
|
|
}
|
|
|
|
void MultiSettings::impl::load_from (Dictionary const& dictionary, bool add_placeholder)
|
|
{
|
|
if (dictionary.size ())
|
|
{
|
|
for (Dictionary::const_iterator iter = dictionary.constBegin ();
|
|
iter != dictionary.constEnd (); ++iter)
|
|
{
|
|
settings_.setValue (iter.key (), iter.value ());
|
|
}
|
|
}
|
|
else if (add_placeholder)
|
|
{
|
|
// add a placeholder key to stop the alternative configuration
|
|
// name from disappearing
|
|
settings_.setValue (multi_settings_place_holder_key, QVariant {});
|
|
}
|
|
settings_.sync ();
|
|
}
|
|
|
|
void MultiSettings::impl::select_configuration (QMainWindow * main_window, QMenu const * menu)
|
|
{
|
|
auto const& target_name = menu->title ();
|
|
|
|
if (target_name != current_)
|
|
{
|
|
{
|
|
auto const& current_group = settings_.group ();
|
|
if (current_group.size ()) settings_.endGroup ();
|
|
// position to the alternative settings
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
// save the target settings
|
|
SettingsGroup target_group {&settings_, target_name};
|
|
new_settings_ = get_settings ();
|
|
if (current_group.size ()) settings_.beginGroup (current_group);
|
|
}
|
|
// and set up the restart
|
|
current_ = target_name;
|
|
Q_EMIT parent_->configurationNameChanged (unescape_ampersands (current_));
|
|
reposition_type_ = RepositionType::save_and_replace;
|
|
exit_flag_ = false;
|
|
main_window->close ();
|
|
}
|
|
}
|
|
|
|
void MultiSettings::impl::clone_configuration (QMainWindow * main_window, QMenu * parent_menu, QMenu const * menu)
|
|
{
|
|
auto const& current_group = settings_.group ();
|
|
if (current_group.size ()) settings_.endGroup ();
|
|
auto const& source_name = menu->title ();
|
|
|
|
// settings to clone
|
|
Dictionary source_settings;
|
|
if (source_name == current_)
|
|
{
|
|
// grab the data to clone from the current settings
|
|
source_settings = get_settings ();
|
|
}
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
if (source_name != current_)
|
|
{
|
|
SettingsGroup source_group {&settings_, source_name};
|
|
source_settings = get_settings ();
|
|
}
|
|
|
|
// find a new unique name
|
|
QString new_name_root {source_name + " - Copy"};;
|
|
QString new_name {new_name_root};
|
|
unsigned index {0};
|
|
do
|
|
{
|
|
if (index++) new_name = new_name_root + '(' + QString::number (index) + ')';
|
|
}
|
|
while (settings_.childGroups ().contains (new_name) || new_name == current_);
|
|
SettingsGroup new_group {&settings_, new_name};
|
|
load_from (source_settings);
|
|
|
|
// insert the new configuration sub menu in the parent menu
|
|
create_sub_menu (main_window, parent_menu, new_name, configurations_group_);
|
|
if (current_group.size ()) settings_.beginGroup (current_group);
|
|
}
|
|
|
|
void MultiSettings::impl::clone_into_configuration (QMainWindow * main_window, QMenu const * menu)
|
|
{
|
|
auto const& current_group = settings_.group ();
|
|
if (current_group.size ()) settings_.endGroup ();
|
|
auto const& target_name = menu->title ();
|
|
|
|
// get the current configuration name
|
|
QString current_group_name;
|
|
QStringList sources;
|
|
{
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
current_group_name = settings_.value (multi_settings_current_name_key).toString ();
|
|
|
|
{
|
|
// get the source configuration name for the clone
|
|
sources = settings_.childGroups ();
|
|
sources << current_group_name;
|
|
sources.removeOne (target_name);
|
|
}
|
|
}
|
|
|
|
// pick a source configuration
|
|
ExistingNameDialog dialog {sources, main_window};
|
|
if (sources.size () && (1 == sources.size () || QDialog::Accepted == dialog.exec ()))
|
|
{
|
|
QString source_name {1 == sources.size () ? sources.at (0) : dialog.name ()};
|
|
if (MessageBox::Yes == MessageBox::query_message (main_window,
|
|
tr ("Clone Into Configuration"),
|
|
tr ("Confirm overwrite of all values for configuration \"%1\" with values from \"%2\"?")
|
|
.arg (unescape_ampersands (target_name))
|
|
.arg (unescape_ampersands (source_name))))
|
|
{
|
|
// grab the data to clone from
|
|
if (source_name == current_group_name)
|
|
{
|
|
// grab the data to clone from the current settings
|
|
new_settings_ = get_settings ();
|
|
}
|
|
else
|
|
{
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
SettingsGroup source_group {&settings_, source_name};
|
|
new_settings_ = get_settings ();
|
|
}
|
|
|
|
// purge target settings and replace
|
|
if (target_name == current_)
|
|
{
|
|
// restart with new settings
|
|
reposition_type_ = RepositionType::replace;
|
|
exit_flag_ = false;
|
|
main_window->close ();
|
|
}
|
|
else
|
|
{
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
SettingsGroup target_group {&settings_, target_name};
|
|
settings_.remove (QString {}); // purge entire group
|
|
load_from (new_settings_);
|
|
new_settings_.clear ();
|
|
}
|
|
}
|
|
}
|
|
if (current_group.size ()) settings_.beginGroup (current_group);
|
|
}
|
|
|
|
void MultiSettings::impl::reset_configuration (QMainWindow * main_window, QMenu const * menu)
|
|
{
|
|
auto const& target_name = menu->title ();
|
|
|
|
if (MessageBox::Yes != MessageBox::query_message (main_window,
|
|
tr ("Reset Configuration"),
|
|
tr ("Confirm reset to default values for configuration \"%1\"?")
|
|
.arg (unescape_ampersands (target_name))))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (target_name == current_)
|
|
{
|
|
// restart with default settings
|
|
reposition_type_ = RepositionType::replace;
|
|
new_settings_.clear ();
|
|
exit_flag_ = false;
|
|
main_window->close ();
|
|
}
|
|
else
|
|
{
|
|
auto const& current_group = settings_.group ();
|
|
if (current_group.size ()) settings_.endGroup ();
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
SettingsGroup target_group {&settings_, target_name};
|
|
settings_.remove (QString {}); // purge entire group
|
|
// add a placeholder to stop alternative configuration name
|
|
// being lost
|
|
settings_.setValue (multi_settings_place_holder_key, QVariant {});
|
|
settings_.sync ();
|
|
if (current_group.size ()) settings_.beginGroup (current_group);
|
|
}
|
|
}
|
|
|
|
void MultiSettings::impl::rename_configuration (QMainWindow * main_window, QMenu * menu)
|
|
{
|
|
auto const& current_group = settings_.group ();
|
|
if (current_group.size ()) settings_.endGroup ();
|
|
auto const& target_name = menu->title ();
|
|
|
|
// gather names we cannot use
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
auto invalid_names = settings_.childGroups ();
|
|
invalid_names << settings_.value (multi_settings_current_name_key).toString ();
|
|
|
|
// get the new name
|
|
NameDialog dialog {target_name, invalid_names, main_window};
|
|
if (QDialog::Accepted == dialog.exec ())
|
|
{
|
|
if (target_name == current_)
|
|
{
|
|
settings_.setValue (multi_settings_current_name_key, dialog.new_name ());
|
|
settings_.sync ();
|
|
current_ = dialog.new_name ();
|
|
Q_EMIT parent_->configurationNameChanged (unescape_ampersands (current_));
|
|
}
|
|
else
|
|
{
|
|
// switch to the target group and fetch the configuration data
|
|
Dictionary target_settings;
|
|
{
|
|
// grab the target configuration settings
|
|
SettingsGroup target_group {&settings_, target_name};
|
|
target_settings = get_settings ();
|
|
// purge the old configuration data
|
|
settings_.remove (QString {}); // purge entire group
|
|
}
|
|
// load into new configuration group name
|
|
SettingsGroup target_group {&settings_, dialog.new_name ()};
|
|
load_from (target_settings);
|
|
}
|
|
// change the action text in the menu
|
|
menu->setTitle (dialog.new_name ());
|
|
}
|
|
if (current_group.size ()) settings_.beginGroup (current_group);
|
|
}
|
|
|
|
void MultiSettings::impl::delete_configuration (QMainWindow * main_window, QMenu * menu)
|
|
{
|
|
auto const& target_name = menu->title ();
|
|
|
|
if (target_name == current_)
|
|
{
|
|
return; // suicide not allowed here
|
|
}
|
|
else
|
|
{
|
|
if (MessageBox::Yes != MessageBox::query_message (main_window,
|
|
tr ("Delete Configuration"),
|
|
tr ("Confirm deletion of configuration \"%1\"?")
|
|
.arg (unescape_ampersands (target_name))))
|
|
{
|
|
return;
|
|
}
|
|
auto const& current_group = settings_.group ();
|
|
if (current_group.size ()) settings_.endGroup ();
|
|
SettingsGroup alternatives {&settings_, multi_settings_root_group};
|
|
SettingsGroup target_group {&settings_, target_name};
|
|
// purge the configuration data
|
|
settings_.remove (QString {}); // purge entire group
|
|
settings_.sync ();
|
|
if (current_group.size ()) settings_.beginGroup (current_group);
|
|
}
|
|
// update the menu
|
|
menu->deleteLater ();
|
|
}
|