From 1f4f95bcba4ece6751c8145a13b7c7254ef3117f Mon Sep 17 00:00:00 2001 From: "Christian T. Jacobs" Date: Sat, 1 Apr 2017 14:57:07 +0100 Subject: [PATCH] Connecting up the Preferences dialog. --- bin/pyqso | 4 +- pyqso/glade/pyqso.glade | 170 +++++---- pyqso/preferences_dialog.py | 662 ++++++++++++------------------------ 3 files changed, 310 insertions(+), 526 deletions(-) diff --git a/bin/pyqso b/bin/pyqso index 3a408eb..299f063 100755 --- a/bin/pyqso +++ b/bin/pyqso @@ -145,10 +145,10 @@ class PyQSO: def show_preferences(self, widget): """ Show the Preferences dialog. Any changes made by the user after clicking the 'Ok' button are saved in the .cfg file. """ preferences = PreferencesDialog(self) - response = preferences.run() + response = preferences.dialog.run() if(response == Gtk.ResponseType.OK): preferences.commit() - preferences.destroy() + preferences.dialog.destroy() return if(__name__ == "__main__"): diff --git a/pyqso/glade/pyqso.glade b/pyqso/glade/pyqso.glade index ae177c0..20b63ee 100644 --- a/pyqso/glade/pyqso.glade +++ b/pyqso/glade/pyqso.glade @@ -1429,7 +1429,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.vertical 2 - + Callsign True True @@ -1446,7 +1446,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. - + Date True True @@ -1463,7 +1463,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. - + Time True True @@ -1480,7 +1480,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. - + Frequency (MHz) True True @@ -1562,7 +1562,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. - + TX Power (W) True True @@ -1596,7 +1596,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. - + RST Received True True @@ -1630,7 +1630,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. - + QSL Received True True @@ -1777,7 +1777,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.vertical 2 - + CQ Zone True True @@ -1794,7 +1794,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. - + ITU Zone True True @@ -1811,7 +1811,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. - + IOTA Designator True True @@ -1878,76 +1878,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.False - - - True - False - vertical - 2 - - - True - False - 0 - - - True - False - - - True - False - vertical - 2 - - - Merge any text in the COMMENT field with the NOTES field - True - True - False - 0 - True - - - False - True - 0 - - - - - - - - - True - False - Import - - - - - True - True - 0 - - - - - 2 - - - - - True - False - Hamlib - - - 4 - False - - True @@ -2208,10 +2138,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. True False - - qrz.com - hamqth.com - False @@ -2397,7 +2323,7 @@ Base64-encoded plain text in the configuration file. - 3 + 2 @@ -2406,6 +2332,76 @@ Base64-encoded plain text in the configuration file. False Records + + 2 + False + + + + + True + False + vertical + 2 + + + True + False + 0 + + + True + False + + + True + False + vertical + 2 + + + Merge any text in the COMMENT field with the NOTES field + True + True + False + 0 + True + + + False + True + 0 + + + + + + + + + True + False + Import + + + + + True + True + 0 + + + + + 3 + + + + + True + False + ADIF + 3 False @@ -2550,10 +2546,10 @@ Base64-encoded plain text in the configuration file. - + True False - ADIF + Hamlib 4 diff --git a/pyqso/preferences_dialog.py b/pyqso/preferences_dialog.py index 9bbc8e6..e5a7fb6 100644 --- a/pyqso/preferences_dialog.py +++ b/pyqso/preferences_dialog.py @@ -17,7 +17,6 @@ # You should have received a copy of the GNU General Public License # along with PyQSO. If not, see . -from gi.repository import Gtk import logging try: import configparser @@ -43,38 +42,31 @@ from pyqso.adif import * PREFERENCES_FILE = os.path.expanduser("~/.config/pyqso/preferences.ini") -class PreferencesDialog(Gtk.Dialog): +class PreferencesDialog: """ A dialog to specify the PyQSO preferences. """ def __init__(self, application): - """ Set up the various pages of the preferences dialog. """ + """ Set up the various pages of the preferences dialog. + + :arg application: The PyQSO application containing the main Gtk window, etc. + """ logging.debug("Setting up the preferences dialog...") self.application = application + self.builder = self.application.builder - Gtk.Dialog.__init__(self, title="Preferences", parent=self.application.window, flags=Gtk.DialogFlags.DESTROY_WITH_PARENT, buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK)) + self.builder.add_objects_from_file(os.path.abspath(os.path.dirname(__file__)) + "/glade/pyqso.glade", ("preferences_dialog",)) + self.dialog = self.builder.get_object("preferences_dialog") - self.preferences = Gtk.Notebook() + self.general = GeneralPage(self.builder) + self.view = ViewPage(self.builder) + self.records = RecordsPage(self.builder) + self.adif = ADIFPage(self.builder) + self.hamlib = HamlibPage(self.builder) - self.general = GeneralPage() - self.preferences.insert_page(self.general, Gtk.Label("General"), 0) - - self.view = ViewPage() - self.preferences.insert_page(self.view, Gtk.Label("View"), 1) - - self.hamlib = HamlibPage() - self.preferences.insert_page(self.hamlib, Gtk.Label("Hamlib"), 2) - - self.records = RecordsPage() - self.preferences.insert_page(self.records, Gtk.Label("Records"), 2) - - self.adif = ADIFPage() - self.preferences.insert_page(self.adif, Gtk.Label("ADIF"), 2) - - self.vbox.pack_start(self.preferences, True, True, 2) - self.show_all() + self.dialog.show_all() logging.debug("Preferences dialog ready!") @@ -84,38 +76,33 @@ class PreferencesDialog(Gtk.Dialog): """ Commit the user preferences to the configuration file. """ logging.debug("Committing the user preferences to the configuration file...") - general_data = self.general.get_data() - view_data = self.view.get_data() - hamlib_data = self.hamlib.get_data() - records_data = self.records.get_data() - adif_data = self.adif.get_data() config = configparser.ConfigParser() # General config.add_section("general") - for key in list(general_data.keys()): - config.set("general", key.lower(), str(general_data[key])) + for key in list(self.general.data.keys()): + config.set("general", key.lower(), str(self.general.data[key])) # View config.add_section("view") - for key in list(view_data.keys()): - config.set("view", key.lower(), str(view_data[key])) - - # ADIF - config.add_section("adif") - for key in list(adif_data.keys()): - config.set("adif", key.lower(), str(adif_data[key])) - - # Hamlib - config.add_section("hamlib") - for key in list(hamlib_data.keys()): - config.set("hamlib", key.lower(), str(hamlib_data[key])) + for key in list(self.view.data.keys()): + config.set("view", key.lower(), str(self.view.data[key])) # Records config.add_section("records") - for key in list(records_data.keys()): - config.set("records", key.lower(), str(records_data[key])) + for key in list(self.records.data.keys()): + config.set("records", key.lower(), str(self.records.data[key])) + + # ADIF + config.add_section("adif") + for key in list(self.adif.data.keys()): + config.set("adif", key.lower(), str(self.adif.data[key])) + + # Hamlib + config.add_section("hamlib") + for key in list(self.hamlib.data.keys()): + config.set("hamlib", key.lower(), str(self.hamlib.data[key])) # Write the preferences to file. with open(os.path.expanduser(PREFERENCES_FILE), 'w') as f: @@ -124,64 +111,47 @@ class PreferencesDialog(Gtk.Dialog): return -class GeneralPage(Gtk.VBox): +class GeneralPage: """ The section of the preferences dialog containing general preferences. """ - def __init__(self): + def __init__(self, builder): logging.debug("Setting up the General page of the preferences dialog...") - Gtk.VBox.__init__(self, spacing=2) + self.builder = builder + self.sources = {} # Remember that the have_config conditional in the PyQSO class may be out-of-date the next time the user opens up the preferences dialog # because a configuration file may have been created after launching the application. Let's check to see if one exists again... config = configparser.ConfigParser() have_config = (config.read(PREFERENCES_FILE) != []) - - self.sources = {} - - # Startup - frame = Gtk.Frame() - frame.set_label("Startup") - - vbox = Gtk.VBox() - + # Show toolbox - hbox = Gtk.HBox() - self.sources["SHOW_TOOLBOX"] = Gtk.CheckButton("Show toolbox by default") + self.sources["SHOW_TOOLBOX"] = self.builder.get_object("general_show_toolbox_checkbutton") (section, option) = ("general", "show_toolbox") if(have_config and config.has_option(section, option)): self.sources["SHOW_TOOLBOX"].set_active(config.get(section, option) == "True") else: self.sources["SHOW_TOOLBOX"].set_active(False) - hbox.pack_start(self.sources["SHOW_TOOLBOX"], False, False, 2) - vbox.pack_start(hbox, False, False, 2) # Show statistics - hbox = Gtk.HBox() - self.sources["SHOW_YEARLY_STATISTICS"] = Gtk.CheckButton("Show yearly logbook statistics on the Summary page") + self.sources["SHOW_YEARLY_STATISTICS"] = self.builder.get_object("general_show_yearly_statistics_checkbutton") (section, option) = ("general", "show_yearly_statistics") if(have_config and config.has_option(section, option)): self.sources["SHOW_YEARLY_STATISTICS"].set_active(config.get(section, option) == "True") else: self.sources["SHOW_YEARLY_STATISTICS"].set_active(False) - hbox.pack_start(self.sources["SHOW_YEARLY_STATISTICS"], False, False, 2) - vbox.pack_start(hbox, False, False, 2) # Default logbook - hbox = Gtk.HBox() - self.sources["DEFAULT_LOGBOOK"] = Gtk.CheckButton("Open a default logbook: ") - + self.sources["DEFAULT_LOGBOOK"] = self.builder.get_object("general_default_logbook_checkbutton") (section, option) = ("general", "default_logbook") if(have_config and config.has_option(section, option)): self.sources["DEFAULT_LOGBOOK"].set_active(config.get(section, option) == "True") else: self.sources["DEFAULT_LOGBOOK"].set_active(False) self.sources["DEFAULT_LOGBOOK"].connect("toggled", self._on_default_logbook_toggled) - hbox.pack_start(self.sources["DEFAULT_LOGBOOK"], False, False, 2) - vbox.pack_start(hbox, False, False, 2) - self.sources["DEFAULT_LOGBOOK_PATH"] = Gtk.Entry() + self.sources["DEFAULT_LOGBOOK_PATH"] = self.builder.get_object("general_default_logbook_entry") (section, option) = ("general", "default_logbook") # Disable the text entry box if the default logbook checkbox is not checked. if(have_config and config.has_option(section, option)): @@ -191,77 +161,29 @@ class GeneralPage(Gtk.VBox): (section, option) = ("general", "default_logbook_path") if(have_config and config.has_option(section, option)): self.sources["DEFAULT_LOGBOOK_PATH"].set_text(config.get(section, option)) - hbox.pack_start(self.sources["DEFAULT_LOGBOOK_PATH"], False, False, 2) - - frame.add(vbox) - self.pack_start(frame, False, False, 2) - - # Dialogs - frame = Gtk.Frame() - frame.set_label("Dialogs") - - vbox = Gtk.VBox() # Keep 'Add Record' dialog open - hbox = Gtk.HBox() - self.sources["KEEP_OPEN"] = Gtk.CheckButton("Keep the Add Record dialog open after a QSO is added") + self.sources["KEEP_OPEN"] = self.builder.get_object("general_keep_open_checkbutton") (section, option) = ("general", "keep_open") if(have_config and config.has_option(section, option)): self.sources["KEEP_OPEN"].set_active(config.get(section, option) == "True") else: self.sources["KEEP_OPEN"].set_active(False) - hbox.pack_start(self.sources["KEEP_OPEN"], False, False, 2) - vbox.pack_start(hbox, False, False, 2) - - frame.add(vbox) - self.pack_start(frame, False, False, 2) - - # QTH - frame = Gtk.Frame() - frame.set_label("QTH") - - vbox = Gtk.VBox() # Pin-point QTH on grey line map. - self.sources["SHOW_QTH"] = Gtk.CheckButton("Pin-point QTH on grey line map") + self.sources["SHOW_QTH"] = self.builder.get_object("general_show_qth_checkbutton") (section, option) = ("general", "show_qth") if(have_config and config.has_option(section, option)): self.sources["SHOW_QTH"].set_active(config.get(section, option) == "True") else: self.sources["SHOW_QTH"].set_active(False) - self.sources["SHOW_QTH"].connect("toggled", self._on_show_qth_toggled) - vbox.pack_start(self.sources["SHOW_QTH"], False, False, 2) - hbox = Gtk.HBox() - label = Gtk.Label("Name:") - label.set_width_chars(10) - label.set_alignment(0, 0.5) - self.sources["QTH_NAME"] = Gtk.Entry() - hbox.pack_start(label, False, False, 2) - hbox.pack_start(self.sources["QTH_NAME"], False, False, 2) - icon = Gtk.Image() - icon.set_from_stock(Gtk.STOCK_INFO, Gtk.IconSize.MENU) - button = Gtk.Button() - button.add(icon) + self.sources["QTH_NAME"] = self.builder.get_object("general_qth_name_entry") + button = self.builder.get_object("general_qth_lookup") button.connect("clicked", self._lookup_callback) # Uses geocoding to find the latitude-longitude coordinates. - button.set_tooltip_text("Lookup QTH coordinates") - hbox.pack_start(button, False, False, 2) - vbox.pack_start(hbox, False, False, 2) - hbox = Gtk.HBox() - label = Gtk.Label("Latitude:") - label.set_width_chars(10) - label.set_alignment(0, 0.5) - self.sources["QTH_LATITUDE"] = Gtk.Entry() - hbox.pack_start(label, False, False, 2) - hbox.pack_start(self.sources["QTH_LATITUDE"], False, False, 2) - label = Gtk.Label("Longitude:") - label.set_width_chars(10) - label.set_alignment(0, 0.5) - self.sources["QTH_LONGITUDE"] = Gtk.Entry() - hbox.pack_start(label, False, False, 2) - hbox.pack_start(self.sources["QTH_LONGITUDE"], False, False, 2) - vbox.pack_start(hbox, False, False, 2) + self.sources["QTH_LATITUDE"] = self.builder.get_object("general_qth_coordinates_latitude_entry") + self.sources["QTH_LONGITUDE"] = self.builder.get_object("general_qth_coordinates_longitude_entry") (section, option) = ("general", "show_qth") # Disable the text entry boxes if the SHOW_QTH checkbox is not checked. @@ -283,13 +205,11 @@ class GeneralPage(Gtk.VBox): if(have_config and config.has_option(section, option)): self.sources["QTH_LONGITUDE"].set_text(config.get(section, option)) - frame.add(vbox) - self.pack_start(frame, False, False, 2) - logging.debug("General page of the preferences dialog ready!") return - def get_data(self): + @property + def data(self): logging.debug("Retrieving data from the General page of the preferences dialog...") data = {} data["SHOW_TOOLBOX"] = self.sources["SHOW_TOOLBOX"].get_active() @@ -339,53 +259,32 @@ class GeneralPage(Gtk.VBox): return -class ViewPage(Gtk.VBox): +class ViewPage: """ The section of the preferences dialog containing view-related preferences. """ - def __init__(self): + def __init__(self, builder): logging.debug("Setting up the View page of the preferences dialog...") - Gtk.VBox.__init__(self, spacing=2) + self.builder = builder + self.sources = {} config = configparser.ConfigParser() have_config = (config.read(PREFERENCES_FILE) != []) - self.sources = {} - - # Visible fields frame - frame = Gtk.Frame() - frame.set_label("Visible fields") - - # Divide the list of available field names up into multiple columns (of maximum length 'max_buttons_per_column') - # so we don't make the Preferences dialog too long. - hbox = Gtk.HBox(spacing=2) - max_buttons_per_column = 6 - number_of_columns = int(len(AVAILABLE_FIELD_NAMES_ORDERED)/max_buttons_per_column) + 1 # Number of check buttons per column - for i in range(0, number_of_columns): - vbox = Gtk.VBox(spacing=2) - for j in range(0, max_buttons_per_column): - if(i*max_buttons_per_column + j >= len(AVAILABLE_FIELD_NAMES_ORDERED)): - break - field_name = AVAILABLE_FIELD_NAMES_ORDERED[i*max_buttons_per_column + j] - button = Gtk.CheckButton(AVAILABLE_FIELD_NAMES_FRIENDLY[field_name]) - if(have_config and config.has_option("view", field_name.lower())): - button.set_active(config.get("view", field_name.lower()) == "True") - else: - button.set_active(True) - self.sources[field_name] = button - vbox.pack_start(button, False, False, 2) - hbox.pack_start(vbox, False, False, 2) - frame.add(hbox) - self.pack_start(frame, False, False, 2) - - self.label = Gtk.Label("Note: View-related changes will not take effect\nuntil PyQSO is restarted.") - self.pack_start(self.label, False, False, 2) + # Visible fields + for field_name in AVAILABLE_FIELD_NAMES_ORDERED: + self.sources[field_name] = self.builder.get_object("visible_fields_%s" % (field_name.lower())) + if(have_config and config.has_option("view", field_name.lower())): + self.sources[field_name].set_active(config.get("view", field_name.lower()) == "True") + else: + self.sources[field_name].set_active(True) logging.debug("View page of the preferences dialog ready!") return - def get_data(self): + @property + def data(self): logging.debug("Retrieving data from the View page of the preferences dialog...") data = {} for field_name in AVAILABLE_FIELD_NAMES_ORDERED: @@ -393,38 +292,181 @@ class ViewPage(Gtk.VBox): return data -class HamlibPage(Gtk.VBox): +class RecordsPage: + + """ The section of the preferences dialog containing record-related preferences. """ + + def __init__(self, builder): + logging.debug("Setting up the Records page of the preferences dialog...") + + self.builder = builder + self.sources = {} + + # Remember that the have_config conditional in the PyQSO class may be out-of-date the next time the user opens up the preferences dialog + # because a configuration file may have been created after launching the application. Let's check to see if one exists again... + config = configparser.ConfigParser() + have_config = (config.read(PREFERENCES_FILE) != []) + + # Autocomplete + self.sources["AUTOCOMPLETE_BAND"] = self.builder.get_object("records_autocomplete_band_checkbutton") + (section, option) = ("records", "autocomplete_band") + if(have_config and config.has_option(section, option)): + self.sources["AUTOCOMPLETE_BAND"].set_active(config.get(section, option) == "True") + else: + self.sources["AUTOCOMPLETE_BAND"].set_active(True) + + self.sources["USE_UTC"] = self.builder.get_object("records_autocomplete_utc_checkbutton") + (section, option) = ("records", "use_utc") + if(have_config and config.has_option(section, option)): + self.sources["USE_UTC"].set_active(config.get(section, option) == "True") + else: + self.sources["USE_UTC"].set_active(True) + + # Default values + + # Mode + self.sources["DEFAULT_MODE"] = self.builder.get_object("default_values_mode_combo") + for mode in sorted(MODES.keys()): + self.sources["DEFAULT_MODE"].append_text(mode) + (section, option) = ("records", "default_mode") + if(have_config and config.has_option(section, option)): + mode = config.get(section, option) + else: + mode = "" + self.sources["DEFAULT_MODE"].set_active(sorted(MODES.keys()).index(mode)) + self.sources["DEFAULT_MODE"].connect("changed", self._on_mode_changed) + + # Submode + self.sources["DEFAULT_SUBMODE"] = self.builder.get_object("default_values_submode_combo") + for submode in MODES[mode]: + self.sources["DEFAULT_SUBMODE"].append_text(submode) + (section, option) = ("records", "default_submode") + if(have_config and config.has_option(section, option)): + submode = config.get(section, option) + else: + submode = "" + self.sources["DEFAULT_SUBMODE"].set_active(MODES[mode].index(submode)) + + # Power + self.sources["DEFAULT_POWER"] = self.builder.get_object("default_values_tx_power_entry") + (section, option) = ("records", "default_power") + if(have_config and config.has_option(section, option)): + self.sources["DEFAULT_POWER"].set_text(config.get(section, option)) + else: + self.sources["DEFAULT_POWER"].set_text("") + + # Callsign lookup + self.sources["CALLSIGN_DATABASE"] = self.builder.get_object("callsign_lookup_database_combo") + callsign_database = ["", "qrz.com", "hamqth.com"] + for database in callsign_database: + self.sources["CALLSIGN_DATABASE"].append_text(database) + (section, option) = ("records", "callsign_database") + if(have_config and config.has_option(section, option)): + self.sources["CALLSIGN_DATABASE"].set_active(callsign_database.index(config.get(section, option))) + else: + self.sources["CALLSIGN_DATABASE"].set_active(callsign_database.index("")) + + # Login details + self.sources["CALLSIGN_DATABASE_USERNAME"] = self.builder.get_object("callsign_lookup_login_details_username_entry") + (section, option) = ("records", "callsign_database_username") + if(have_config and config.has_option(section, option)): + self.sources["CALLSIGN_DATABASE_USERNAME"].set_text(config.get(section, option)) + + self.sources["CALLSIGN_DATABASE_PASSWORD"] = self.builder.get_object("callsign_lookup_login_details_password_entry") + (section, option) = ("records", "callsign_database_password") + if(have_config and config.has_option(section, option)): + password = base64.b64decode(config.get(section, option)).decode("utf-8") + self.sources["CALLSIGN_DATABASE_PASSWORD"].set_text(password) + + self.sources["IGNORE_PREFIX_SUFFIX"] = self.builder.get_object("callsign_lookup_ignore_prefix_suffix_checkbutton") + (section, option) = ("records", "ignore_prefix_suffix") + if(have_config and config.has_option(section, option)): + self.sources["IGNORE_PREFIX_SUFFIX"].set_active(config.get(section, option) == "True") + else: + self.sources["IGNORE_PREFIX_SUFFIX"].set_active(True) + + logging.debug("Records page of the preferences dialog ready!") + return + + @property + def data(self): + logging.debug("Retrieving data from the Records page of the preferences dialog...") + data = {} + data["AUTOCOMPLETE_BAND"] = self.sources["AUTOCOMPLETE_BAND"].get_active() + data["USE_UTC"] = self.sources["USE_UTC"].get_active() + + data["DEFAULT_MODE"] = self.sources["DEFAULT_MODE"].get_active_text() + data["DEFAULT_SUBMODE"] = self.sources["DEFAULT_SUBMODE"].get_active_text() + data["DEFAULT_POWER"] = self.sources["DEFAULT_POWER"].get_text() + + data["CALLSIGN_DATABASE"] = self.sources["CALLSIGN_DATABASE"].get_active_text() + data["CALLSIGN_DATABASE_USERNAME"] = self.sources["CALLSIGN_DATABASE_USERNAME"].get_text() + data["CALLSIGN_DATABASE_PASSWORD"] = base64.b64encode(self.sources["CALLSIGN_DATABASE_PASSWORD"].get_text().encode("utf-8")).decode("utf-8") # Need to convert from bytes to str here. + data["IGNORE_PREFIX_SUFFIX"] = self.sources["IGNORE_PREFIX_SUFFIX"].get_active() + return data + + def _on_mode_changed(self, combo): + """ If the MODE field has changed its value, then fill the SUBMODE field with all the available SUBMODE options for that new MODE. """ + self.sources["DEFAULT_SUBMODE"].get_model().clear() + mode = combo.get_active_text() + for submode in MODES[mode]: + self.sources["DEFAULT_SUBMODE"].append_text(submode) + return + + +class ADIFPage: + + """ The section of the preferences dialog containing ADIF-related preferences. """ + + def __init__(self, builder): + logging.debug("Setting up the ADIF page of the preferences dialog...") + + self.builder = builder + self.sources = {} + + # Remember that the have_config conditional in the PyQSO class may be out-of-date the next time the user opens up the preferences dialog + # because a configuration file may have been created after launching the application. Let's check to see if one exists again... + config = configparser.ConfigParser() + have_config = (config.read(PREFERENCES_FILE) != []) + + # Import + self.sources["MERGE_COMMENT"] = self.builder.get_object("adif_import_merge_comment_checkbutton") + (section, option) = ("adif", "merge_comment") + if(have_config and config.has_option(section, option)): + self.sources["MERGE_COMMENT"].set_active(config.get(section, option) == "True") + else: + self.sources["MERGE_COMMENT"].set_active(False) + + logging.debug("ADIF page of the preferences dialog ready!") + return + + @property + def data(self): + logging.debug("Retrieving data from the ADIF page of the preferences dialog...") + data = {} + data["MERGE_COMMENT"] = self.sources["MERGE_COMMENT"].get_active() + return data + + +class HamlibPage: """ The section of the preferences dialog containing Hamlib-related preferences. """ - def __init__(self): + def __init__(self, builder): logging.debug("Setting up the Hamlib page of the preferences dialog...") - Gtk.VBox.__init__(self, spacing=2) + self.builder = builder + self.sources = {} config = configparser.ConfigParser() have_config = (config.read(PREFERENCES_FILE) != []) - self.sources = {} - - frame = Gtk.Frame() - frame.set_label("Hamlib support") - - vbox_inner = Gtk.VBox(spacing=2) - - self.sources["AUTOFILL"] = Gtk.CheckButton("Auto-fill Frequency and Mode fields") + self.sources["AUTOFILL"] = self.builder.get_object("hamlib_support_checkbutton") (section, option) = ("hamlib", "autofill") if(have_config and config.has_option(section, option)): self.sources["AUTOFILL"].set_active(config.get(section, option) == "True") else: self.sources["AUTOFILL"].set_active(False) - vbox_inner.pack_start(self.sources["AUTOFILL"], False, False, 2) - - hbox_temp = Gtk.HBox(spacing=0) - label = Gtk.Label("Model: ") - label.set_alignment(0, 0.5) - label.set_width_chars(17) - hbox_temp.pack_start(label, False, False, 2) # Get the list of rig models models = ["RIG_MODEL_NONE"] @@ -438,7 +480,7 @@ class HamlibPage(Gtk.VBox): else: logging.debug("Hamlib module not present. Could not obtain a list of rig models.") - self.sources["RIG_MODEL"] = Gtk.ComboBoxText() + self.sources["RIG_MODEL"] = self.builder.get_object("hamlib_support_model_combo") for model in models: self.sources["RIG_MODEL"].append_text(model) (section, option) = ("hamlib", "rig_model") @@ -446,275 +488,21 @@ class HamlibPage(Gtk.VBox): self.sources["RIG_MODEL"].set_active(models.index(config.get("hamlib", "rig_model"))) else: self.sources["RIG_MODEL"].set_active(models.index("RIG_MODEL_NONE")) # Set to RIG_MODEL_NONE as the default option. - hbox_temp.pack_start(self.sources["RIG_MODEL"], True, True, 2) - vbox_inner.pack_start(hbox_temp, False, False, 2) # Path to rig - hbox_temp = Gtk.HBox() - label = Gtk.Label("Path to radio device: ") - label.set_width_chars(17) - label.set_alignment(0, 0.5) - hbox_temp.pack_start(label, False, False, 2) - self.sources["RIG_PATHNAME"] = Gtk.Entry() + self.sources["RIG_PATHNAME"] = self.builder.get_object("hamlib_support_path_entry") (section, option) = ("hamlib", "rig_pathname") if(have_config and config.has_option(section, option)): self.sources["RIG_PATHNAME"].set_text(config.get(section, option)) - hbox_temp.pack_start(self.sources["RIG_PATHNAME"], True, True, 2) - vbox_inner.pack_start(hbox_temp, False, False, 2) - - frame.add(vbox_inner) - self.pack_start(frame, True, True, 2) logging.debug("Hamlib page of the preferences dialog ready!") return - def get_data(self): + @property + def data(self): logging.debug("Retrieving data from the Hamlib page of the preferences dialog...") data = {} data["AUTOFILL"] = self.sources["AUTOFILL"].get_active() data["RIG_PATHNAME"] = self.sources["RIG_PATHNAME"].get_text() data["RIG_MODEL"] = self.sources["RIG_MODEL"].get_active_text() return data - - -class RecordsPage(Gtk.VBox): - - """ The section of the preferences dialog containing record-related preferences. """ - - def __init__(self): - logging.debug("Setting up the Records page of the preferences dialog...") - - Gtk.VBox.__init__(self, spacing=2) - - # Remember that the have_config conditional in the PyQSO class may be out-of-date the next time the user opens up the preferences dialog - # because a configuration file may have been created after launching the application. Let's check to see if one exists again... - config = configparser.ConfigParser() - have_config = (config.read(PREFERENCES_FILE) != []) - - self.sources = {} - - # Autocomplete frame - frame = Gtk.Frame() - frame.set_label("Autocomplete") - vbox = Gtk.VBox() - self.sources["AUTOCOMPLETE_BAND"] = Gtk.CheckButton("Autocomplete the Band field") - (section, option) = ("records", "autocomplete_band") - if(have_config and config.has_option(section, option)): - self.sources["AUTOCOMPLETE_BAND"].set_active(config.get(section, option) == "True") - else: - self.sources["AUTOCOMPLETE_BAND"].set_active(True) - vbox.pack_start(self.sources["AUTOCOMPLETE_BAND"], False, False, 2) - - self.sources["USE_UTC"] = Gtk.CheckButton("Use UTC when autocompleting the Date and Time") - (section, option) = ("records", "use_utc") - if(have_config and config.has_option(section, option)): - self.sources["USE_UTC"].set_active(config.get(section, option) == "True") - else: - self.sources["USE_UTC"].set_active(True) - vbox.pack_start(self.sources["USE_UTC"], False, False, 2) - - frame.add(vbox) - self.pack_start(frame, False, False, 2) - - # Default values frame - frame = Gtk.Frame() - frame.set_label("Default values") - vbox = Gtk.VBox() - - # Mode - hbox_temp = Gtk.HBox() - label = Gtk.Label("Mode: ") - label.set_width_chars(17) - label.set_alignment(0, 0.5) - hbox_temp.pack_start(label, False, False, 2) - - self.sources["DEFAULT_MODE"] = Gtk.ComboBoxText() - for mode in sorted(MODES.keys()): - self.sources["DEFAULT_MODE"].append_text(mode) - (section, option) = ("records", "default_mode") - if(have_config and config.has_option(section, option)): - mode = config.get(section, option) - else: - mode = "" - self.sources["DEFAULT_MODE"].set_active(sorted(MODES.keys()).index(mode)) - self.sources["DEFAULT_MODE"].connect("changed", self._on_mode_changed) - hbox_temp.pack_start(self.sources["DEFAULT_MODE"], False, False, 2) - vbox.pack_start(hbox_temp, False, False, 2) - - # Submode - hbox_temp = Gtk.HBox() - label = Gtk.Label("Submode: ") - label.set_width_chars(17) - label.set_alignment(0, 0.5) - hbox_temp.pack_start(label, False, False, 2) - - self.sources["DEFAULT_SUBMODE"] = Gtk.ComboBoxText() - for submode in MODES[mode]: - self.sources["DEFAULT_SUBMODE"].append_text(submode) - (section, option) = ("records", "default_submode") - if(have_config and config.has_option(section, option)): - submode = config.get(section, option) - else: - submode = "" - self.sources["DEFAULT_SUBMODE"].set_active(MODES[mode].index(submode)) - hbox_temp.pack_start(self.sources["DEFAULT_SUBMODE"], False, False, 2) - vbox.pack_start(hbox_temp, False, False, 2) - - # Power - hbox_temp = Gtk.HBox() - label = Gtk.Label("TX Power (W): ") - label.set_width_chars(17) - label.set_alignment(0, 0.5) - hbox_temp.pack_start(label, False, False, 2) - - self.sources["DEFAULT_POWER"] = Gtk.Entry() - (section, option) = ("records", "default_power") - if(have_config and config.has_option(section, option)): - self.sources["DEFAULT_POWER"].set_text(config.get(section, option)) - else: - self.sources["DEFAULT_POWER"].set_text("") - hbox_temp.pack_start(self.sources["DEFAULT_POWER"], False, False, 2) - vbox.pack_start(hbox_temp, False, False, 2) - - frame.add(vbox) - self.pack_start(frame, False, False, 2) - - # Callsign lookup frame - frame = Gtk.Frame() - frame.set_label("Callsign lookup") - vbox = Gtk.VBox() - - # Callsign database - hbox_temp = Gtk.HBox() - label = Gtk.Label("Database: ") - label.set_width_chars(17) - label.set_alignment(0, 0.5) - hbox_temp.pack_start(label, False, False, 2) - - self.sources["CALLSIGN_DATABASE"] = Gtk.ComboBoxText() - callsign_database = ["", "qrz.com", "hamqth.com"] - for database in callsign_database: - self.sources["CALLSIGN_DATABASE"].append_text(database) - (section, option) = ("records", "callsign_database") - if(have_config and config.has_option(section, option)): - self.sources["CALLSIGN_DATABASE"].set_active(callsign_database.index(config.get(section, option))) - else: - self.sources["CALLSIGN_DATABASE"].set_active(callsign_database.index("")) - hbox_temp.pack_start(self.sources["CALLSIGN_DATABASE"], False, False, 2) - vbox.pack_start(hbox_temp, False, False, 2) - - # Login details - subframe = Gtk.Frame() - subframe.set_label("Login details") - inner_vbox = Gtk.VBox() - - hbox = Gtk.HBox() - label = Gtk.Label("Username: ") - label.set_width_chars(15) - label.set_alignment(0, 0.5) - hbox.pack_start(label, False, False, 2) - self.sources["CALLSIGN_DATABASE_USERNAME"] = Gtk.Entry() - (section, option) = ("records", "callsign_database_username") - if(have_config and config.has_option(section, option)): - self.sources["CALLSIGN_DATABASE_USERNAME"].set_text(config.get(section, option)) - hbox.pack_start(self.sources["CALLSIGN_DATABASE_USERNAME"], False, False, 2) - inner_vbox.pack_start(hbox, False, False, 2) - - hbox = Gtk.HBox() - label = Gtk.Label("Password: ") - label.set_width_chars(15) - label.set_alignment(0, 0.5) - hbox.pack_start(label, False, False, 2) - self.sources["CALLSIGN_DATABASE_PASSWORD"] = Gtk.Entry() - self.sources["CALLSIGN_DATABASE_PASSWORD"].set_visibility(False) # Mask the password with the "*" character. - (section, option) = ("records", "callsign_database_password") - if(have_config and config.has_option(section, option)): - password = base64.b64decode(config.get(section, option)).decode("utf-8") - self.sources["CALLSIGN_DATABASE_PASSWORD"].set_text(password) - hbox.pack_start(self.sources["CALLSIGN_DATABASE_PASSWORD"], False, False, 2) - inner_vbox.pack_start(hbox, False, False, 2) - - label = Gtk.Label("Warning: Login details are currently stored as\nBase64-encoded plain text in the configuration file.") - inner_vbox.pack_start(label, False, False, 2) - - subframe.add(inner_vbox) - vbox.pack_start(subframe, False, False, 2) - - self.sources["IGNORE_PREFIX_SUFFIX"] = Gtk.CheckButton("Ignore callsign prefixes and/or suffixes") - (section, option) = ("records", "ignore_prefix_suffix") - if(have_config and config.has_option(section, option)): - self.sources["IGNORE_PREFIX_SUFFIX"].set_active(config.get(section, option) == "True") - else: - self.sources["IGNORE_PREFIX_SUFFIX"].set_active(True) - vbox.pack_start(self.sources["IGNORE_PREFIX_SUFFIX"], False, False, 2) - - frame.add(vbox) - self.pack_start(frame, False, False, 2) - - logging.debug("Records page of the preferences dialog ready!") - return - - def get_data(self): - logging.debug("Retrieving data from the Records page of the preferences dialog...") - data = {} - data["AUTOCOMPLETE_BAND"] = self.sources["AUTOCOMPLETE_BAND"].get_active() - data["USE_UTC"] = self.sources["USE_UTC"].get_active() - - data["DEFAULT_MODE"] = self.sources["DEFAULT_MODE"].get_active_text() - data["DEFAULT_SUBMODE"] = self.sources["DEFAULT_SUBMODE"].get_active_text() - data["DEFAULT_POWER"] = self.sources["DEFAULT_POWER"].get_text() - - data["CALLSIGN_DATABASE"] = self.sources["CALLSIGN_DATABASE"].get_active_text() - data["CALLSIGN_DATABASE_USERNAME"] = self.sources["CALLSIGN_DATABASE_USERNAME"].get_text() - data["CALLSIGN_DATABASE_PASSWORD"] = base64.b64encode(self.sources["CALLSIGN_DATABASE_PASSWORD"].get_text().encode("utf-8")).decode('utf-8') # Need to convert from bytes to str here. - data["IGNORE_PREFIX_SUFFIX"] = self.sources["IGNORE_PREFIX_SUFFIX"].get_active() - return data - - def _on_mode_changed(self, combo): - """ If the MODE field has changed its value, then fill the SUBMODE field with all the available SUBMODE options for that new MODE. """ - self.sources["DEFAULT_SUBMODE"].get_model().clear() - mode = combo.get_active_text() - for submode in MODES[mode]: - self.sources["DEFAULT_SUBMODE"].append_text(submode) - return - - -class ADIFPage(Gtk.VBox): - - """ The section of the preferences dialog containing ADIF-related preferences. """ - - def __init__(self): - logging.debug("Setting up the ADIF page of the preferences dialog...") - - Gtk.VBox.__init__(self, spacing=2) - - # Remember that the have_config conditional in the PyQSO class may be out-of-date the next time the user opens up the preferences dialog - # because a configuration file may have been created after launching the application. Let's check to see if one exists again... - config = configparser.ConfigParser() - have_config = (config.read(PREFERENCES_FILE) != []) - - self.sources = {} - - # Import frame - frame = Gtk.Frame() - frame.set_label("Import") - vbox = Gtk.VBox() - self.sources["MERGE_COMMENT"] = Gtk.CheckButton("Merge any text in the COMMENT field with the NOTES field.") - (section, option) = ("adif", "merge_comment") - if(have_config and config.has_option(section, option)): - self.sources["MERGE_COMMENT"].set_active(config.get(section, option) == "True") - else: - self.sources["MERGE_COMMENT"].set_active(False) - vbox.pack_start(self.sources["MERGE_COMMENT"], False, False, 2) - - frame.add(vbox) - self.pack_start(frame, False, False, 2) - - logging.debug("ADIF page of the preferences dialog ready!") - return - - def get_data(self): - logging.debug("Retrieving data from the ADIF page of the preferences dialog...") - data = {} - data["MERGE_COMMENT"] = self.sources["MERGE_COMMENT"].get_active() - return data