diff --git a/CMakeLists.txt b/CMakeLists.txt index e20041eea..923be021a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -236,6 +236,7 @@ set (wsjt_qt_CXXSRCS MultiSettings.cpp MaidenheadLocatorValidator.cpp CallsignValidator.cpp + SplashScreen.cpp ) set (wsjt_qtmm_CXXSRCS diff --git a/MultiSettings.cpp b/MultiSettings.cpp index 8f483849f..7f1e423da 100644 --- a/MultiSettings.cpp +++ b/MultiSettings.cpp @@ -217,6 +217,44 @@ 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 (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); @@ -287,6 +325,8 @@ MultiSettings::impl::impl () // 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: @@ -337,6 +377,7 @@ bool MultiSettings::impl::reposition () new_settings_.clear (); break; } + if (current_group.size ()) settings_.beginGroup (current_group); reposition_type_ = RepositionType::unchanged; // reset bool exit {exit_flag_}; @@ -349,6 +390,8 @@ bool MultiSettings::impl::reposition () // 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 current_configuration_name = settings_.value (multi_settings_current_name_key, tr (default_string)).toString (); @@ -386,6 +429,7 @@ void MultiSettings::impl::create_menu_actions (QMainWindow * main_window, QMenu action_connections_ << connect (delete_action_, &QAction::triggered, [this, main_window] (bool) { delete_configuration (main_window); }); + if (current_group.size ()) settings_.beginGroup (current_group); } // call this at the end of the main program loop to determine if the @@ -422,8 +466,11 @@ QMenu * MultiSettings::impl::create_sub_menu (QMenu * parent_menu, bool is_current {sub_menu->menuAction ()->text () == current_}; select_action_->setEnabled (!is_current); delete_action_->setEnabled (!is_current); + auto const& current_group = settings_.group (); + if (current_group.size ()) settings_.endGroup (); SettingsGroup alternatives {&settings_, multi_settings_root_group}; clone_into_action_->setEnabled (settings_.childGroups ().size ()); + if (current_group.size ()) settings_.beginGroup (current_group); active_sub_menu_ = sub_menu; }); @@ -474,11 +521,14 @@ void MultiSettings::impl::select_configuration (QMainWindow * main_window) 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; @@ -493,6 +543,8 @@ void MultiSettings::impl::clone_configuration (QMenu * menu) { if (active_sub_menu_) { + auto const& current_group = settings_.group (); + if (current_group.size ()) settings_.endGroup (); auto const& source_name = active_sub_menu_->title (); // settings to clone @@ -523,6 +575,7 @@ void MultiSettings::impl::clone_configuration (QMenu * menu) // insert the new configuration sub menu in the parent menu create_sub_menu (menu, new_name, configurations_group_); + if (current_group.size ()) settings_.beginGroup (current_group); } } @@ -530,6 +583,8 @@ void MultiSettings::impl::clone_into_configuration (QMainWindow * main_window) { if (active_sub_menu_) { + auto const& current_group = settings_.group (); + if (current_group.size ()) settings_.endGroup (); auto const& target_name = active_sub_menu_->title (); // get the current configuration name @@ -589,6 +644,7 @@ void MultiSettings::impl::clone_into_configuration (QMainWindow * main_window) } } } + if (current_group.size ()) settings_.beginGroup (current_group); } } @@ -616,6 +672,8 @@ void MultiSettings::impl::reset_configuration (QMainWindow * main_window) } 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 (""); // purge entire group @@ -623,6 +681,7 @@ void MultiSettings::impl::reset_configuration (QMainWindow * main_window) // being lost settings_.setValue (multi_settings_place_holder_key, QVariant {}); settings_.sync (); + if (current_group.size ()) settings_.beginGroup (current_group); } } } @@ -631,6 +690,8 @@ void MultiSettings::impl::rename_configuration (QMainWindow * main_window) { if (active_sub_menu_) { + auto const& current_group = settings_.group (); + if (current_group.size ()) settings_.endGroup (); auto const& target_name = active_sub_menu_->title (); // gather names we cannot use @@ -666,6 +727,7 @@ void MultiSettings::impl::rename_configuration (QMainWindow * main_window) // change the action text in the menu active_sub_menu_->setTitle (dialog.new_name ()); } + if (current_group.size ()) settings_.beginGroup (current_group); } } @@ -688,11 +750,14 @@ void MultiSettings::impl::delete_configuration (QMainWindow * main_window) { 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 (""); // purge entire group settings_.sync (); + if (current_group.size ()) settings_.beginGroup (current_group); } // update the menu active_sub_menu_->deleteLater (), active_sub_menu_ = nullptr; diff --git a/MultiSettings.hpp b/MultiSettings.hpp index 80e1b49a7..1fdc0308f 100644 --- a/MultiSettings.hpp +++ b/MultiSettings.hpp @@ -1,10 +1,14 @@ -#ifndef MULTISETTINGS_HPP_ +#ifndef MULTISETTINGS_HPP__ +#define MULTISETTINGS_HPP__ + +#include #include "pimpl_h.hpp" class QSettings; class QMainWindow; class QMenu; +class QString; // // MultiSettings - Manage multiple configuration names @@ -71,6 +75,11 @@ public: // Access to the QSettings object instance. QSettings * settings (); + // Access to values in a common section + QVariant common_value (QString const& key, QVariant const& default_value = QVariant {}) const; + void set_common_value (QString const& key, QVariant const& value); + void remove_common_value (QString const& key); + // Call this to determine if the application is terminating, if it // returns false then the application main window should be // recreated, shown and the application exec() function called diff --git a/SplashScreen.cpp b/SplashScreen.cpp new file mode 100644 index 000000000..cdeed79b3 --- /dev/null +++ b/SplashScreen.cpp @@ -0,0 +1,51 @@ +#include "SplashScreen.hpp" + +#include +#include +#include +#include + +#include "revision_utils.hpp" +#include "pimpl_impl.hpp" + +class SplashScreen::impl +{ +public: + impl () + : checkbox_ {"Do not show this again"} + { + main_layout_.addStretch (); + main_layout_.addWidget (&checkbox_, 0, Qt::AlignRight); + } + + QVBoxLayout main_layout_; + QCheckBox checkbox_; +}; + +SplashScreen::SplashScreen () + : QSplashScreen {QPixmap {":/splash.png"}, Qt::WindowStaysOnTopHint} +{ + setLayout (&m_->main_layout_); + showMessage ("

" + QString {"Alpha Release: WSJT-X v" + + QCoreApplication::applicationVersion() + " " + + revision ()}.simplified () + "

" + "V1.7 has many new features, most aimed at VHF/UHF/Microwave users.
" + "Some are not yet described in the User Guide and may not be thoroughly
" + "tested. The release notes have more details.

" + "As a test user you have an obligation to report anomalous results
" + "to the development team. We are particularly interested in tests
" + "of experimental modes QRA64 (intended for EME) and MSK144
" + "(intended for meteor scatter).

" + "Send reports to wsjtgroup@yahoogroups.com, and be sure to save .wav
" + "files where appropriate.

" + "Open the Help menu and select Release Notes for more details.
" + "" + "", Qt::AlignCenter); + connect (&m_->checkbox_, &QCheckBox::stateChanged, [this] (int s) { + if (Qt::Checked == s) Q_EMIT disabled (); + }); +} + +SplashScreen::~SplashScreen () +{ +} diff --git a/SplashScreen.hpp b/SplashScreen.hpp new file mode 100644 index 000000000..6bf7712c6 --- /dev/null +++ b/SplashScreen.hpp @@ -0,0 +1,24 @@ +#ifndef SPLASH_SCREEN_HPP___ +#define SPLASH_SCREEN_HPP___ + +#include + +#include "pimpl_h.hpp" + +class SplashScreen final + : public QSplashScreen +{ + Q_OBJECT; + +public: + SplashScreen (); + ~SplashScreen (); + + Q_SIGNAL void disabled (); + +private: + class impl; + pimpl m_; +}; + +#endif diff --git a/main.cpp b/main.cpp index bc077beb7..89272f3bd 100644 --- a/main.cpp +++ b/main.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #if QT_VERSION >= 0x050200 #include @@ -37,6 +36,7 @@ #include "lib/init_random_seed.h" #include "Radio.hpp" #include "FrequencyList.hpp" +#include "SplashScreen.hpp" #include "MessageBox.hpp" // last to avoid nasty MS macro definitions extern "C" { @@ -105,27 +105,6 @@ int main(int argc, char *argv[]) // instantiating QApplication so // that GUI has correct l18n - QPixmap splash_pic {":/splash.png"}; - QSplashScreen splash {splash_pic, Qt::WindowStaysOnTopHint}; - splash.setWindowTitle (QString {}); - splash.showMessage ("

" + QString {"Alpha Release: WSJT-X v" + - QCoreApplication::applicationVersion() + " " + - revision ()}.simplified () + "

" - "V1.7 has many new features, most aimed at VHF/UHF/Microwave users.
" - "Some are not yet described in the User Guide and may not be thoroughly
" - "tested. The release notes have more details.

" - "As a test user you have an obligation to report anomalous results
" - "to the development team. We are particularly interested in tests
" - "of experimental modes QRA64 (intended for EME) and MSK144
" - "(intended for meteor scatter).

" - "Send reports to wsjtgroup@yahoogroups.com, and be sure to save .wav
" - "files where appropriate.

" - "Open the Help menu and select Release Notes for more details.
" - "" - "", Qt::AlignCenter); - splash.show (); - a.processEvents (); - // Override programs executable basename as application name. a.setApplicationName ("WSJT-X"); a.setApplicationVersion (version ()); @@ -148,7 +127,6 @@ int main(int argc, char *argv[]) if (!parser.parse (a.arguments ())) { - splash.hide (); MessageBox::critical_message (nullptr, a.translate ("main", "Command line error"), parser.errorText ()); return -1; } @@ -156,13 +134,11 @@ int main(int argc, char *argv[]) { if (parser.isSet (help_option)) { - splash.hide (); MessageBox::information_message (nullptr, a.translate ("main", "Command line help"), parser.helpText ()); return 0; } else if (parser.isSet (version_option)) { - splash.hide (); MessageBox::information_message (nullptr, a.translate ("main", "Application version"), a.applicationVersion ()); return 0; } @@ -193,6 +169,8 @@ int main(int argc, char *argv[]) multiple = true; } + // now we have the application name we can open the settings + MultiSettings multi_settings; // find the temporary files path QDir temp_dir {QStandardPaths::writableLocation (QStandardPaths::TempLocation)}; @@ -206,7 +184,6 @@ int main(int argc, char *argv[]) { if (QLockFile::LockFailedError == instance_lock.error ()) { - splash.hide (); auto button = MessageBox::query_message (nullptr , a.translate ("main", "Another instance may be running") , a.translate ("main", "try to remove stale lock file?") @@ -225,7 +202,6 @@ int main(int argc, char *argv[]) default: throw std::runtime_error {"Multiple instances must have unique rig names"}; } - splash.show (); } } #endif @@ -244,7 +220,6 @@ int main(int argc, char *argv[]) if (!temp_dir.mkpath (unique_directory) || !temp_dir.cd (unique_directory)) { - splash.hide (); MessageBox::critical_message (nullptr, a.translate ("main", "Failed to create a temporary directory"), a.translate ("main", "Path: \"%1\"").arg (temp_dir.absolutePath ())); @@ -252,7 +227,6 @@ int main(int argc, char *argv[]) } if (!temp_dir.isReadable () || !(temp_ok = QTemporaryFile {temp_dir.absoluteFilePath ("test")}.open ())) { - splash.hide (); auto button = MessageBox::critical_message (nullptr, a.translate ("main", "Failed to create a usable temporary directory"), a.translate ("main", "Another application may be locking the directory"), @@ -262,13 +236,27 @@ int main(int argc, char *argv[]) { throw std::runtime_error {"Failed to create a usable temporary directory"}; } - splash.show (); temp_dir.cdUp (); // revert to parent as this one is no good } } while (!temp_ok); - MultiSettings multi_settings; + SplashScreen splash; + { + // change this key if you want to force a new splash screen + // for a new version, the user will be able to re-disable it + // if they wish + QString splash_flag_name {"Splash_v1.7"}; + if (multi_settings.common_value (splash_flag_name, true).toBool ()) + { + QObject::connect (&splash, &SplashScreen::disabled, [&, splash_flag_name] { + multi_settings.set_common_value (splash_flag_name, false); + splash.close (); + }); + splash.show (); + a.processEvents (); + } + } int result; do