kopia lustrzana https://github.com/ctjacobs/pyqso
Added a new menu item for updating the ADIF modes from the ADIF website. Addresses issue #69.
rodzic
091da72806
commit
2487424839
|
@ -85,6 +85,7 @@ class PyQSO:
|
||||||
# Kills the application if the close button is clicked on the main window itself.
|
# Kills the application if the close button is clicked on the main window itself.
|
||||||
self.window.connect("delete-event", Gtk.main_quit)
|
self.window.connect("delete-event", Gtk.main_quit)
|
||||||
|
|
||||||
|
# Status bar.
|
||||||
self.statusbar = self.builder.get_object("statusbar")
|
self.statusbar = self.builder.get_object("statusbar")
|
||||||
context_id = self.statusbar.get_context_id("Status")
|
context_id = self.statusbar.get_context_id("Status")
|
||||||
self.statusbar.push(context_id, "No logbook is currently open.")
|
self.statusbar.push(context_id, "No logbook is currently open.")
|
||||||
|
|
|
@ -27,6 +27,8 @@ except ImportError:
|
||||||
import ConfigParser as configparser
|
import ConfigParser as configparser
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
|
|
||||||
|
from pyqso.modes import Modes
|
||||||
|
|
||||||
# ADIF field names and their associated data types available in PyQSO.
|
# ADIF field names and their associated data types available in PyQSO.
|
||||||
AVAILABLE_FIELD_NAMES_TYPES = {"CALL": "S",
|
AVAILABLE_FIELD_NAMES_TYPES = {"CALL": "S",
|
||||||
"QSO_DATE": "D",
|
"QSO_DATE": "D",
|
||||||
|
@ -98,98 +100,6 @@ AVAILABLE_FIELD_NAMES_FRIENDLY = {"CALL": "Callsign",
|
||||||
# E: Enumerated
|
# E: Enumerated
|
||||||
DATA_TYPES = ["A", "B", "N", "S", "I", "D", "T", "M", "G", "L", "E"]
|
DATA_TYPES = ["A", "B", "N", "S", "I", "D", "T", "M", "G", "L", "E"]
|
||||||
|
|
||||||
# All the valid modes listed in the ADIF specification. This is a dictionary with the key-value pairs holding the MODE and SUBMODE(s) respectively.
|
|
||||||
MODES = {"": ("",),
|
|
||||||
"AM": ("",),
|
|
||||||
"ATV": ("",),
|
|
||||||
"CHIP": ("", "CHIP64", "CHIP128"),
|
|
||||||
"CLO": ("",),
|
|
||||||
"CONTESTI": ("",),
|
|
||||||
"CW": ("", "PCW"),
|
|
||||||
"DIGITALVOICE": ("",),
|
|
||||||
"DOMINO": ("", "DOMINOEX", "DOMINOF"),
|
|
||||||
"DSTAR": ("",),
|
|
||||||
"FAX": ("",),
|
|
||||||
"FM": ("",),
|
|
||||||
"FSK441": ("",),
|
|
||||||
"FT8": ("",),
|
|
||||||
"HELL": ("", "FMHELL", "FSKHELL", "HELL80", "HFSK", "PSKHELL"),
|
|
||||||
"ISCAT": ("", "ISCAT-A", "ISCAT-B"),
|
|
||||||
"JT4": ("", "JT4A", "JT4B", "JT4C", "JT4D", "JT4E", "JT4F", "JT4G"),
|
|
||||||
"JT6M": ("",),
|
|
||||||
"JT9": ("",),
|
|
||||||
"JT44": ("",),
|
|
||||||
"JT65": ("", "JT65A", "JT65B", "JT65B2", "JT65C", "JT65C2"),
|
|
||||||
"MFSK": ("", "MFSK4", "MFSK8", "MFSK11", "MFSK16", "MFSK22", "MFSK31", "MFSK32", "MFSK64", "MFSK128"),
|
|
||||||
"MT63": ("",),
|
|
||||||
"OLIVIA": ("", "OLIVIA 4/125", "OLIVIA 4/250", "OLIVIA 8/250", "OLIVIA 8/500", "OLIVIA 16/500", "OLIVIA 16/1000", "OLIVIA 32/1000"),
|
|
||||||
"OPERA": ("", "OPERA-BEACON", "OPERA-QSO"),
|
|
||||||
"PAC": ("", "PAC2", "PAC3", "PAC4"),
|
|
||||||
"PAX": ("", "PAX2"),
|
|
||||||
"PKT": ("",),
|
|
||||||
"PSK": ("", "FSK31", "PSK10", "PSK31", "PSK63", "PSK63F", "PSK125", "PSK250", "PSK500", "PSK1000", "PSKAM10", "PSKAM31", "PSKAM50", "PSKFEC31", "QPSK31", "QPSK63", "QPSK125", "QPSK250", "QPSK500"),
|
|
||||||
"PSK2K": ("",),
|
|
||||||
"Q15": ("",),
|
|
||||||
"ROS": ("", "ROS-EME", "ROS-HF", "ROS-MF"),
|
|
||||||
"RTTY": ("", "ASCI"),
|
|
||||||
"RTTYM": ("",),
|
|
||||||
"SSB": ("", "LSB", "USB"),
|
|
||||||
"SSTV": ("",),
|
|
||||||
"THOR": ("",),
|
|
||||||
"THRB": ("", "THRBX"),
|
|
||||||
"TOR": ("", "AMTORFEC", "GTOR"),
|
|
||||||
"V4": ("",),
|
|
||||||
"VOI": ("",),
|
|
||||||
"WINMOR": ("",),
|
|
||||||
"WSPR": ("",)
|
|
||||||
}
|
|
||||||
|
|
||||||
# A dictionary of all the deprecated MODE values.
|
|
||||||
MODES_DEPRECATED = {"AMTORFEC": ("",),
|
|
||||||
"ASCI": ("",),
|
|
||||||
"CHIP64": ("",),
|
|
||||||
"CHIP128": ("",),
|
|
||||||
"DOMINOF": ("",),
|
|
||||||
"FMHELL": ("",),
|
|
||||||
"FSK31": ("",),
|
|
||||||
"GTOR": ("",),
|
|
||||||
"HELL80": ("",),
|
|
||||||
"HFSK": ("",),
|
|
||||||
"JT4A": ("",),
|
|
||||||
"JT4B": ("",),
|
|
||||||
"JT4C": ("",),
|
|
||||||
"JT4D": ("",),
|
|
||||||
"JT4E": ("",),
|
|
||||||
"JT4F": ("",),
|
|
||||||
"JT4G": ("",),
|
|
||||||
"JT65A": ("",),
|
|
||||||
"JT65B": ("",),
|
|
||||||
"JT65C": ("",),
|
|
||||||
"MFSK8": ("",),
|
|
||||||
"MFSK16": ("",),
|
|
||||||
"PAC2": ("",),
|
|
||||||
"PAC3": ("",),
|
|
||||||
"PAX2": ("",),
|
|
||||||
"PCW": ("",),
|
|
||||||
"PSK10": ("",),
|
|
||||||
"PSK31": ("",),
|
|
||||||
"PSK63": ("",),
|
|
||||||
"PSK63F": ("",),
|
|
||||||
"PSK125": ("",),
|
|
||||||
"PSKAM10": ("",),
|
|
||||||
"PSKAM31": ("",),
|
|
||||||
"PSKAM50": ("",),
|
|
||||||
"PSKFEC31": ("",),
|
|
||||||
"PSKHELL": ("",),
|
|
||||||
"QPSK31": ("",),
|
|
||||||
"QPSK63": ("",),
|
|
||||||
"QPSK125": ("",),
|
|
||||||
"THRBX": ("",)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Include all deprecated modes.
|
|
||||||
MODES.update(MODES_DEPRECATED)
|
|
||||||
|
|
||||||
# All the bands listed in the ADIF specification.
|
# All the bands listed in the ADIF specification.
|
||||||
BANDS = ["", "2190m", "630m", "560m", "160m", "80m", "60m", "40m", "30m", "20m", "17m", "15m", "12m", "10m", "6m", "4m", "2m", "1.25m", "70cm", "33cm", "23cm", "13cm", "9cm", "6cm", "3cm", "1.25cm", "6mm", "4mm", "2.5mm", "2mm", "1mm"]
|
BANDS = ["", "2190m", "630m", "560m", "160m", "80m", "60m", "40m", "30m", "20m", "17m", "15m", "12m", "10m", "6m", "4m", "2m", "1.25m", "70cm", "33cm", "23cm", "13cm", "9cm", "6cm", "3cm", "1.25cm", "6mm", "4mm", "2.5mm", "2mm", "1mm"]
|
||||||
# The lower and upper frequency bounds (in MHz) for each band in BANDS.
|
# The lower and upper frequency bounds (in MHz) for each band in BANDS.
|
||||||
|
@ -207,6 +117,7 @@ class ADIF:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
""" Initialise class for I/O of files using the Amateur Data Interchange Format (ADIF). """
|
""" Initialise class for I/O of files using the Amateur Data Interchange Format (ADIF). """
|
||||||
|
self.modes = Modes()
|
||||||
return
|
return
|
||||||
|
|
||||||
def read(self, path):
|
def read(self, path):
|
||||||
|
@ -521,9 +432,9 @@ class ADIF:
|
||||||
elif(data_type == "E" or data_type == "A"):
|
elif(data_type == "E" or data_type == "A"):
|
||||||
# Enumeration, AwardList.
|
# Enumeration, AwardList.
|
||||||
if(field_name == "MODE"):
|
if(field_name == "MODE"):
|
||||||
return (data in list(MODES.keys()))
|
return (data in list(self.modes.all.keys()))
|
||||||
elif(field_name == "SUBMODE"):
|
elif(field_name == "SUBMODE"):
|
||||||
submodes = [submode for mode in list(MODES.keys()) for submode in MODES[mode]]
|
submodes = [submode for mode in list(self.modes.all.keys()) for submode in self.modes.all[mode]]
|
||||||
return (data in submodes)
|
return (data in submodes)
|
||||||
elif(field_name == "BAND"):
|
elif(field_name == "BAND"):
|
||||||
return (data in BANDS)
|
return (data in BANDS)
|
||||||
|
|
|
@ -38,6 +38,7 @@ from pyqso.summary import Summary
|
||||||
from pyqso.blank import Blank
|
from pyqso.blank import Blank
|
||||||
from pyqso.printer import Printer
|
from pyqso.printer import Printer
|
||||||
from pyqso.compare import compare_date_and_time, compare_default
|
from pyqso.compare import compare_date_and_time, compare_default
|
||||||
|
from pyqso.update_modes_dialog import UpdateModesDialog
|
||||||
|
|
||||||
|
|
||||||
class Logbook:
|
class Logbook:
|
||||||
|
@ -907,7 +908,7 @@ class Logbook:
|
||||||
return
|
return
|
||||||
log = self.logs[log_index]
|
log = self.logs[log_index]
|
||||||
|
|
||||||
(sort_model, path) = self.treeselection[log_index].get_selected_rows() # Get the selected row in the log
|
(sort_model, path) = self.treeselection[log_index].get_selected_rows() # Get the selected row in the log.
|
||||||
try:
|
try:
|
||||||
sort_iter = sort_model.get_iter(path[0])
|
sort_iter = sort_model.get_iter(path[0])
|
||||||
filter_iter = self.sorter[log_index].convert_iter_to_child_iter(sort_iter)
|
filter_iter = self.sorter[log_index].convert_iter_to_child_iter(sort_iter)
|
||||||
|
@ -1113,6 +1114,16 @@ class Logbook:
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def update_modes_callback(self, widget=None, path=None):
|
||||||
|
umd = UpdateModesDialog(self.application)
|
||||||
|
response = umd.dialog.run()
|
||||||
|
if(response == Gtk.ResponseType.OK):
|
||||||
|
modes = Modes()
|
||||||
|
modes.update(url=umd.url)
|
||||||
|
umd.dialog.destroy()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def log_count(self):
|
def log_count(self):
|
||||||
""" Return the total number of logs in the logbook.
|
""" Return the total number of logs in the logbook.
|
||||||
|
|
|
@ -109,6 +109,10 @@ class Menu:
|
||||||
self.items["RECORD_COUNT"] = self.builder.get_object("mitem_record_count")
|
self.items["RECORD_COUNT"] = self.builder.get_object("mitem_record_count")
|
||||||
self.items["RECORD_COUNT"].connect("activate", self.application.logbook.record_count_callback)
|
self.items["RECORD_COUNT"].connect("activate", self.application.logbook.record_count_callback)
|
||||||
|
|
||||||
|
# Record count
|
||||||
|
self.items["UPDATE_MODES"] = self.builder.get_object("mitem_update_modes")
|
||||||
|
self.items["UPDATE_MODES"].connect("activate", self.application.logbook.update_modes_callback)
|
||||||
|
|
||||||
# View toolbox
|
# View toolbox
|
||||||
self.items["TOOLBOX"] = self.builder.get_object("mitem_toolbox")
|
self.items["TOOLBOX"] = self.builder.get_object("mitem_toolbox")
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
|
|
180
pyqso/modes.py
180
pyqso/modes.py
|
@ -17,24 +17,192 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PyQSO. If not, see <http://www.gnu.org/licenses/>.
|
# along with PyQSO. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sqlite3
|
||||||
|
import os
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
import logging
|
||||||
|
|
||||||
page = urlopen('http://www.adif.org/307/ADIF_307.htm').read()
|
MODES_FILE = os.path.expanduser("~/.config/pyqso/modes.db")
|
||||||
|
|
||||||
|
|
||||||
|
class Modes:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
try:
|
||||||
|
connection = sqlite3.connect(MODES_FILE)
|
||||||
|
c = connection.cursor()
|
||||||
|
c.execute("""CREATE TABLE IF NOT EXISTS modes (
|
||||||
|
mode TEXT NOT NULL,
|
||||||
|
submode TEXT NOT NULL,
|
||||||
|
UNIQUE(mode, submode)
|
||||||
|
); """)
|
||||||
|
|
||||||
|
# Fill the new table with the basic list of modes and submodes.
|
||||||
|
for mode in self.basic:
|
||||||
|
for submode in self.basic[mode]:
|
||||||
|
c.execute("""REPLACE INTO modes(mode, submode) VALUES(?, ?)""", (mode, submode))
|
||||||
|
connection.commit()
|
||||||
|
connection.close()
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
logging.exception(e)
|
||||||
|
|
||||||
|
#self.update("http://www.adif.org/309/ADIF_309.htm")
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def basic(self):
|
||||||
|
""" A basic list of valid modes listed in the ADIF specification.
|
||||||
|
This is a dictionary with the key-value pairs holding the MODE and SUBMODE(s) respectively. """
|
||||||
|
|
||||||
|
modes = {"": ("",),
|
||||||
|
"AM": ("",),
|
||||||
|
"ATV": ("",),
|
||||||
|
"CHIP": ("", "CHIP64", "CHIP128"),
|
||||||
|
"CLO": ("",),
|
||||||
|
"CONTESTI": ("",),
|
||||||
|
"CW": ("", "PCW"),
|
||||||
|
"DIGITALVOICE": ("",),
|
||||||
|
"DOMINO": ("", "DOMINOEX", "DOMINOF"),
|
||||||
|
"DSTAR": ("",),
|
||||||
|
"FAX": ("",),
|
||||||
|
"FM": ("",),
|
||||||
|
"FSK441": ("",),
|
||||||
|
"FT8": ("",),
|
||||||
|
"HELL": ("", "FMHELL", "FSKHELL", "HELL80", "HFSK", "PSKHELL"),
|
||||||
|
"ISCAT": ("", "ISCAT-A", "ISCAT-B"),
|
||||||
|
"JT4": ("", "JT4A", "JT4B", "JT4C", "JT4D", "JT4E", "JT4F", "JT4G"),
|
||||||
|
"JT6M": ("",),
|
||||||
|
"JT9": ("",),
|
||||||
|
"JT44": ("",),
|
||||||
|
"JT65": ("", "JT65A", "JT65B", "JT65B2", "JT65C", "JT65C2"),
|
||||||
|
"MFSK": ("", "MFSK4", "MFSK8", "MFSK11", "MFSK16", "MFSK22", "MFSK31", "MFSK32", "MFSK64", "MFSK128"),
|
||||||
|
"MT63": ("",),
|
||||||
|
"OLIVIA": ("", "OLIVIA 4/125", "OLIVIA 4/250", "OLIVIA 8/250", "OLIVIA 8/500", "OLIVIA 16/500", "OLIVIA 16/1000", "OLIVIA 32/1000"),
|
||||||
|
"OPERA": ("", "OPERA-BEACON", "OPERA-QSO"),
|
||||||
|
"PAC": ("", "PAC2", "PAC3", "PAC4"),
|
||||||
|
"PAX": ("", "PAX2"),
|
||||||
|
"PKT": ("",),
|
||||||
|
"PSK": ("", "FSK31", "PSK10", "PSK31", "PSK63", "PSK63F", "PSK125", "PSK250", "PSK500", "PSK1000", "PSKAM10", "PSKAM31", "PSKAM50", "PSKFEC31", "QPSK31", "QPSK63", "QPSK125", "QPSK250", "QPSK500"),
|
||||||
|
"PSK2K": ("",),
|
||||||
|
"Q15": ("",),
|
||||||
|
"ROS": ("", "ROS-EME", "ROS-HF", "ROS-MF"),
|
||||||
|
"RTTY": ("", "ASCI"),
|
||||||
|
"RTTYM": ("",),
|
||||||
|
"SSB": ("", "LSB", "USB"),
|
||||||
|
"SSTV": ("",),
|
||||||
|
"THOR": ("",),
|
||||||
|
"THRB": ("", "THRBX"),
|
||||||
|
"TOR": ("", "AMTORFEC", "GTOR"),
|
||||||
|
"V4": ("",),
|
||||||
|
"VOI": ("",),
|
||||||
|
"WINMOR": ("",),
|
||||||
|
"WSPR": ("",)
|
||||||
|
}
|
||||||
|
|
||||||
|
# A dictionary of all the deprecated MODE values.
|
||||||
|
deprecated = {"AMTORFEC": ("",),
|
||||||
|
"ASCI": ("",),
|
||||||
|
"CHIP64": ("",),
|
||||||
|
"CHIP128": ("",),
|
||||||
|
"DOMINOF": ("",),
|
||||||
|
"FMHELL": ("",),
|
||||||
|
"FSK31": ("",),
|
||||||
|
"GTOR": ("",),
|
||||||
|
"HELL80": ("",),
|
||||||
|
"HFSK": ("",),
|
||||||
|
"JT4A": ("",),
|
||||||
|
"JT4B": ("",),
|
||||||
|
"JT4C": ("",),
|
||||||
|
"JT4D": ("",),
|
||||||
|
"JT4E": ("",),
|
||||||
|
"JT4F": ("",),
|
||||||
|
"JT4G": ("",),
|
||||||
|
"JT65A": ("",),
|
||||||
|
"JT65B": ("",),
|
||||||
|
"JT65C": ("",),
|
||||||
|
"MFSK8": ("",),
|
||||||
|
"MFSK16": ("",),
|
||||||
|
"PAC2": ("",),
|
||||||
|
"PAC3": ("",),
|
||||||
|
"PAX2": ("",),
|
||||||
|
"PCW": ("",),
|
||||||
|
"PSK10": ("",),
|
||||||
|
"PSK31": ("",),
|
||||||
|
"PSK63": ("",),
|
||||||
|
"PSK63F": ("",),
|
||||||
|
"PSK125": ("",),
|
||||||
|
"PSKAM10": ("",),
|
||||||
|
"PSKAM31": ("",),
|
||||||
|
"PSKAM50": ("",),
|
||||||
|
"PSKFEC31": ("",),
|
||||||
|
"PSKHELL": ("",),
|
||||||
|
"QPSK31": ("",),
|
||||||
|
"QPSK63": ("",),
|
||||||
|
"QPSK125": ("",),
|
||||||
|
"THRBX": ("",)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Include all deprecated modes.
|
||||||
|
modes.update(deprecated)
|
||||||
|
return modes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def all(self):
|
||||||
|
try:
|
||||||
|
connection = sqlite3.connect(MODES_FILE)
|
||||||
|
c = connection.cursor()
|
||||||
|
result = c.execute("""SELECT * FROM modes""")
|
||||||
|
rows = result.fetchall()
|
||||||
|
|
||||||
|
modes = {}
|
||||||
|
for row in rows:
|
||||||
|
mode = row[0]
|
||||||
|
submode = row[1]
|
||||||
|
if(mode in modes.keys()):
|
||||||
|
modes[mode].append(submode)
|
||||||
|
else:
|
||||||
|
modes[mode] = [submode]
|
||||||
|
connection.close()
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
logging.exception(e)
|
||||||
|
return modes
|
||||||
|
|
||||||
|
def update(self, url):
|
||||||
|
modes = self.parse(url)
|
||||||
|
try:
|
||||||
|
connection = sqlite3.connect(MODES_FILE)
|
||||||
|
c = connection.cursor()
|
||||||
|
for mode in modes:
|
||||||
|
for submode in modes[mode]:
|
||||||
|
c.execute("REPLACE INTO modes(mode, submode) VALUES(?,?)", (mode, submode))
|
||||||
|
connection.commit()
|
||||||
|
connection.close()
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
logging.exception(e)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def parse(self, url):
|
||||||
|
page = urlopen(url).read()
|
||||||
soup = BeautifulSoup(page, "html.parser")
|
soup = BeautifulSoup(page, "html.parser")
|
||||||
|
|
||||||
# Remove the <span> tags but keep the tags' contents.
|
# Remove the <span> tags but keep the tags' contents.
|
||||||
for match in soup.findAll('span'):
|
for match in soup.findAll("span"):
|
||||||
match.unwrap()
|
match.unwrap()
|
||||||
|
|
||||||
# Find the MODES table.
|
# Find the MODES table.
|
||||||
rows = soup.find(id="Enumeration_Mode").find_all('tr')
|
rows = soup.find(id="Enumeration_Mode").find_all("tr")
|
||||||
|
|
||||||
# Extract modes and submodes.
|
# Extract modes and submodes.
|
||||||
modes = {}
|
modes = {}
|
||||||
for row in rows[1:]:
|
for row in rows[1:]: # Ignores the header row.
|
||||||
mode, submode, description = row.find_all('td')
|
mode, submode = row.find_all("td")[0:2]
|
||||||
mode = mode.text.split(" (import-only)")[0].strip()
|
mode = mode.text.split(" (import-only)")[0].strip()
|
||||||
submode = tuple(submode.text.strip().split(", "))
|
submode = tuple(submode.text.strip().split(", "))
|
||||||
|
if(mode not in modes):
|
||||||
modes[mode] = submode
|
modes[mode] = submode
|
||||||
print(modes)
|
|
||||||
|
return modes
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,8 @@ except ImportError:
|
||||||
logging.warning("Could not import the geocoder module!")
|
logging.warning("Could not import the geocoder module!")
|
||||||
have_geocoder = False
|
have_geocoder = False
|
||||||
|
|
||||||
from pyqso.adif import AVAILABLE_FIELD_NAMES_ORDERED, MODES
|
from pyqso.adif import AVAILABLE_FIELD_NAMES_ORDERED
|
||||||
|
from pyqso.modes import Modes
|
||||||
from pyqso.auxiliary_dialogs import error
|
from pyqso.auxiliary_dialogs import error
|
||||||
|
|
||||||
PREFERENCES_FILE = os.path.expanduser("~/.config/pyqso/preferences.ini")
|
PREFERENCES_FILE = os.path.expanduser("~/.config/pyqso/preferences.ini")
|
||||||
|
@ -289,27 +290,28 @@ class RecordsPage:
|
||||||
# Default values
|
# Default values
|
||||||
|
|
||||||
# Mode
|
# Mode
|
||||||
|
self.modes = Modes()
|
||||||
self.sources["DEFAULT_MODE"] = self.builder.get_object("default_values_mode_combo")
|
self.sources["DEFAULT_MODE"] = self.builder.get_object("default_values_mode_combo")
|
||||||
for mode in sorted(MODES.keys()):
|
for mode in sorted(self.modes.all.keys()):
|
||||||
self.sources["DEFAULT_MODE"].append_text(mode)
|
self.sources["DEFAULT_MODE"].append_text(mode)
|
||||||
(section, option) = ("records", "default_mode")
|
(section, option) = ("records", "default_mode")
|
||||||
if(have_config and config.has_option(section, option)):
|
if(have_config and config.has_option(section, option)):
|
||||||
mode = config.get(section, option)
|
mode = config.get(section, option)
|
||||||
else:
|
else:
|
||||||
mode = ""
|
mode = ""
|
||||||
self.sources["DEFAULT_MODE"].set_active(sorted(MODES.keys()).index(mode))
|
self.sources["DEFAULT_MODE"].set_active(sorted(self.modes.all.keys()).index(mode))
|
||||||
self.sources["DEFAULT_MODE"].connect("changed", self.on_mode_changed)
|
self.sources["DEFAULT_MODE"].connect("changed", self.on_mode_changed)
|
||||||
|
|
||||||
# Submode
|
# Submode
|
||||||
self.sources["DEFAULT_SUBMODE"] = self.builder.get_object("default_values_submode_combo")
|
self.sources["DEFAULT_SUBMODE"] = self.builder.get_object("default_values_submode_combo")
|
||||||
for submode in MODES[mode]:
|
for submode in self.modes.all[mode]:
|
||||||
self.sources["DEFAULT_SUBMODE"].append_text(submode)
|
self.sources["DEFAULT_SUBMODE"].append_text(submode)
|
||||||
(section, option) = ("records", "default_submode")
|
(section, option) = ("records", "default_submode")
|
||||||
if(have_config and config.has_option(section, option)):
|
if(have_config and config.has_option(section, option)):
|
||||||
submode = config.get(section, option)
|
submode = config.get(section, option)
|
||||||
else:
|
else:
|
||||||
submode = ""
|
submode = ""
|
||||||
self.sources["DEFAULT_SUBMODE"].set_active(MODES[mode].index(submode))
|
self.sources["DEFAULT_SUBMODE"].set_active(self.modes.all[mode].index(submode))
|
||||||
|
|
||||||
# Power
|
# Power
|
||||||
self.sources["DEFAULT_POWER"] = self.builder.get_object("default_values_tx_power_entry")
|
self.sources["DEFAULT_POWER"] = self.builder.get_object("default_values_tx_power_entry")
|
||||||
|
@ -384,9 +386,9 @@ class RecordsPage:
|
||||||
""" If the MODE field has changed its value, then fill the SUBMODE field with all the available SUBMODE options for that new MODE. """
|
""" 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()
|
self.sources["DEFAULT_SUBMODE"].get_model().clear()
|
||||||
mode = combo.get_active_text()
|
mode = combo.get_active_text()
|
||||||
for submode in MODES[mode]:
|
for submode in self.modes.all[mode]:
|
||||||
self.sources["DEFAULT_SUBMODE"].append_text(submode)
|
self.sources["DEFAULT_SUBMODE"].append_text(submode)
|
||||||
self.sources["DEFAULT_SUBMODE"].set_active(MODES[mode].index(""))
|
self.sources["DEFAULT_SUBMODE"].set_active(self.modes.all[mode].index(""))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@ -406,8 +408,8 @@ class ImportExportPage:
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
have_config = (config.read(PREFERENCES_FILE) != [])
|
have_config = (config.read(PREFERENCES_FILE) != [])
|
||||||
|
|
||||||
# Import
|
# ADIF
|
||||||
self.sources["MERGE_COMMENT"] = self.builder.get_object("adif_import_merge_comment_checkbutton")
|
self.sources["MERGE_COMMENT"] = self.builder.get_object("adif_merge_comment_checkbutton")
|
||||||
(section, option) = ("import_export", "merge_comment")
|
(section, option) = ("import_export", "merge_comment")
|
||||||
if(have_config and config.has_option(section, option)):
|
if(have_config and config.has_option(section, option)):
|
||||||
self.sources["MERGE_COMMENT"].set_active(config.getboolean(section, option))
|
self.sources["MERGE_COMMENT"].set_active(config.getboolean(section, option))
|
||||||
|
|
|
@ -104,8 +104,9 @@ class RecordDialog:
|
||||||
self.sources["BAND"].set_active(0) # Set an empty string as the default option.
|
self.sources["BAND"].set_active(0) # Set an empty string as the default option.
|
||||||
|
|
||||||
# MODE
|
# MODE
|
||||||
|
self.modes = Modes().all
|
||||||
self.sources["MODE"] = self.builder.get_object("qso_mode_combo")
|
self.sources["MODE"] = self.builder.get_object("qso_mode_combo")
|
||||||
for mode in sorted(MODES.keys()):
|
for mode in sorted(self.modes.keys()):
|
||||||
self.sources["MODE"].append_text(mode)
|
self.sources["MODE"].append_text(mode)
|
||||||
self.sources["MODE"].set_active(0) # Set an empty string as the default option.
|
self.sources["MODE"].set_active(0) # Set an empty string as the default option.
|
||||||
self.sources["MODE"].connect("changed", self.on_mode_changed)
|
self.sources["MODE"].connect("changed", self.on_mode_changed)
|
||||||
|
@ -199,12 +200,12 @@ class RecordDialog:
|
||||||
converted = self.convert_frequency(data, from_unit="MHz", to_unit=self.frequency_unit)
|
converted = self.convert_frequency(data, from_unit="MHz", to_unit=self.frequency_unit)
|
||||||
self.sources[field_names[i]].set_text(str(converted))
|
self.sources[field_names[i]].set_text(str(converted))
|
||||||
elif(field_names[i] == "MODE"):
|
elif(field_names[i] == "MODE"):
|
||||||
self.sources[field_names[i]].set_active(sorted(MODES.keys()).index(data))
|
self.sources[field_names[i]].set_active(sorted(self.modes.keys()).index(data))
|
||||||
# Handle SUBMODE at the same time.
|
# Handle SUBMODE at the same time.
|
||||||
submode_data = record["submode"]
|
submode_data = record["submode"]
|
||||||
if(submode_data is None):
|
if(submode_data is None):
|
||||||
submode_data = ""
|
submode_data = ""
|
||||||
self.sources["SUBMODE"].set_active(MODES[data].index(submode_data))
|
self.sources["SUBMODE"].set_active(self.modes[data].index(submode_data))
|
||||||
elif(field_names[i] == "SUBMODE"):
|
elif(field_names[i] == "SUBMODE"):
|
||||||
# Skip, because this has been (or will be) handled when populating the MODE field.
|
# Skip, because this has been (or will be) handled when populating the MODE field.
|
||||||
continue
|
continue
|
||||||
|
@ -227,7 +228,7 @@ class RecordDialog:
|
||||||
mode = config.get(section, option)
|
mode = config.get(section, option)
|
||||||
else:
|
else:
|
||||||
mode = ""
|
mode = ""
|
||||||
self.sources["MODE"].set_active(sorted(MODES.keys()).index(mode))
|
self.sources["MODE"].set_active(sorted(self.modes.keys()).index(mode))
|
||||||
|
|
||||||
# Submode
|
# Submode
|
||||||
(section, option) = ("records", "default_submode")
|
(section, option) = ("records", "default_submode")
|
||||||
|
@ -235,7 +236,7 @@ class RecordDialog:
|
||||||
submode = config.get(section, option)
|
submode = config.get(section, option)
|
||||||
else:
|
else:
|
||||||
submode = ""
|
submode = ""
|
||||||
self.sources["SUBMODE"].set_active(MODES[mode].index(submode))
|
self.sources["SUBMODE"].set_active(self.modes[mode].index(submode))
|
||||||
|
|
||||||
# Power
|
# Power
|
||||||
(section, option) = ("records", "default_power")
|
(section, option) = ("records", "default_power")
|
||||||
|
@ -303,9 +304,9 @@ class RecordDialog:
|
||||||
""" If the MODE field has changed its value, then fill the SUBMODE field with all the available SUBMODE options for that new MODE. """
|
""" 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["SUBMODE"].get_model().clear()
|
self.sources["SUBMODE"].get_model().clear()
|
||||||
mode = combo.get_active_text()
|
mode = combo.get_active_text()
|
||||||
for submode in MODES[mode]:
|
for submode in self.modes[mode]:
|
||||||
self.sources["SUBMODE"].append_text(submode)
|
self.sources["SUBMODE"].append_text(submode)
|
||||||
self.sources["SUBMODE"].set_active(MODES[mode].index("")) # Set the submode to an empty string.
|
self.sources["SUBMODE"].set_active(self.modes[mode].index("")) # Set the submode to an empty string.
|
||||||
return
|
return
|
||||||
|
|
||||||
def on_key_press(self, widget, event):
|
def on_key_press(self, widget, event):
|
||||||
|
@ -375,10 +376,10 @@ class RecordDialog:
|
||||||
if(mode == "USB" or mode == "LSB"):
|
if(mode == "USB" or mode == "LSB"):
|
||||||
submode = mode
|
submode = mode
|
||||||
mode = "SSB"
|
mode = "SSB"
|
||||||
self.sources["MODE"].set_active(sorted(MODES.keys()).index(mode))
|
self.sources["MODE"].set_active(sorted(self.modes.keys()).index(mode))
|
||||||
self.sources["SUBMODE"].set_active(MODES[mode].index(submode))
|
self.sources["SUBMODE"].set_active(self.modes[mode].index(submode))
|
||||||
else:
|
else:
|
||||||
self.sources["MODE"].set_active(sorted(MODES.keys()).index(mode))
|
self.sources["MODE"].set_active(sorted(self.modes.keys()).index(mode))
|
||||||
except:
|
except:
|
||||||
logging.error("Could not obtain the current mode (e.g. FM, AM, CW) via Hamlib!")
|
logging.error("Could not obtain the current mode (e.g. FM, AM, CW) via Hamlib!")
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Generated with glade 3.18.3 -->
|
<!-- Generated with glade 3.22.1 -->
|
||||||
<interface>
|
<interface>
|
||||||
<requires lib="gtk+" version="3.10"/>
|
<requires lib="gtk+" version="3.10"/>
|
||||||
<object class="GtkImage" id="image1">
|
<object class="GtkImage" id="image1">
|
||||||
|
@ -68,6 +68,12 @@
|
||||||
<property name="stock">gtk-open</property>
|
<property name="stock">gtk-open</property>
|
||||||
<property name="icon_size">1</property>
|
<property name="icon_size">1</property>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkImage" id="image25">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-refresh</property>
|
||||||
|
<property name="icon_size">1</property>
|
||||||
|
</object>
|
||||||
<object class="GtkImage" id="image29">
|
<object class="GtkImage" id="image29">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
@ -128,6 +134,9 @@
|
||||||
<property name="default_width">800</property>
|
<property name="default_width">800</property>
|
||||||
<property name="default_height">600</property>
|
<property name="default_height">600</property>
|
||||||
<property name="icon">log_64x64.png</property>
|
<property name="icon">log_64x64.png</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox" id="vbox_outer">
|
<object class="GtkBox" id="vbox_outer">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -364,6 +373,28 @@
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem" id="mitem_adif">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">ADIF</property>
|
||||||
|
<child type="submenu">
|
||||||
|
<object class="GtkMenu" id="subm_adif">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="mitem_update_modes">
|
||||||
|
<property name="label" translatable="yes">Update Modes</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="image">image25</property>
|
||||||
|
<property name="use_stock">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkMenuItem" id="mitem_view">
|
<object class="GtkMenuItem" id="mitem_view">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -927,6 +958,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.</pro
|
||||||
<property name="authors">Christian Thomas Jacobs, M0UOS</property>
|
<property name="authors">Christian Thomas Jacobs, M0UOS</property>
|
||||||
<property name="logo">log_64x64.png</property>
|
<property name="logo">log_64x64.png</property>
|
||||||
<property name="license_type">custom</property>
|
<property name="license_type">custom</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="about_dialog_vbox">
|
<object class="GtkBox" id="about_dialog_vbox">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
@ -956,6 +990,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.</pro
|
||||||
<property name="destroy_with_parent">True</property>
|
<property name="destroy_with_parent">True</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<property name="transient_for">pyqso</property>
|
<property name="transient_for">pyqso</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="cabrillo_export_dialog_vbox">
|
<object class="GtkBox" id="cabrillo_export_dialog_vbox">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
@ -1098,6 +1135,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.</pro
|
||||||
<property name="destroy_with_parent">True</property>
|
<property name="destroy_with_parent">True</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<property name="transient_for">pyqso</property>
|
<property name="transient_for">pyqso</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="log_name_dialog_vbox">
|
<object class="GtkBox" id="log_name_dialog_vbox">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
@ -1195,6 +1235,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.</pro
|
||||||
<property name="destroy_with_parent">True</property>
|
<property name="destroy_with_parent">True</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<property name="transient_for">pyqso</property>
|
<property name="transient_for">pyqso</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="preferences_dialog_vbox">
|
<object class="GtkBox" id="preferences_dialog_vbox">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
@ -2505,7 +2548,7 @@ Base64-encoded plain text in the configuration file.</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="spacing">2</property>
|
<property name="spacing">2</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkFrame" id="preferences_adif_import">
|
<object class="GtkFrame" id="preferences_adif">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="label_xalign">0</property>
|
<property name="label_xalign">0</property>
|
||||||
|
@ -2522,7 +2565,7 @@ Base64-encoded plain text in the configuration file.</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="spacing">2</property>
|
<property name="spacing">2</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="adif_import_merge_comment_checkbutton">
|
<object class="GtkCheckButton" id="adif_merge_comment_checkbutton">
|
||||||
<property name="label" translatable="yes">Merge any text in the COMMENT field with the NOTES field</property>
|
<property name="label" translatable="yes">Merge any text in the COMMENT field with the NOTES field</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
|
@ -2541,10 +2584,10 @@ Base64-encoded plain text in the configuration file.</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child type="label">
|
<child type="label">
|
||||||
<object class="GtkLabel" id="preferences_adif_import_label">
|
<object class="GtkLabel" id="preferences_adif_label">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="label" translatable="yes">ADIF Import</property>
|
<property name="label" translatable="yes">ADIF</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
@ -3029,6 +3072,9 @@ Base64-encoded plain text in the configuration file.</property>
|
||||||
<property name="destroy_with_parent">True</property>
|
<property name="destroy_with_parent">True</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<property name="transient_for">pyqso</property>
|
<property name="transient_for">pyqso</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="record_dialog_vbox">
|
<object class="GtkBox" id="record_dialog_vbox">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
@ -4343,6 +4389,9 @@ Base64-encoded plain text in the configuration file.</property>
|
||||||
<property name="destroy_with_parent">True</property>
|
<property name="destroy_with_parent">True</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<property name="transient_for">record_dialog</property>
|
<property name="transient_for">record_dialog</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="calendar_dialog_vbox">
|
<object class="GtkBox" id="calendar_dialog_vbox">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
@ -4415,6 +4464,9 @@ Base64-encoded plain text in the configuration file.</property>
|
||||||
<property name="destroy_with_parent">True</property>
|
<property name="destroy_with_parent">True</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<property name="transient_for">pyqso</property>
|
<property name="transient_for">pyqso</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox" id="telnet_connection_dialog_vbox">
|
<object class="GtkBox" id="telnet_connection_dialog_vbox">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
@ -4658,6 +4710,106 @@ Base64-encoded plain text in the configuration file.</property>
|
||||||
<action-widget response="-5">telnet_connection_ok_button</action-widget>
|
<action-widget response="-5">telnet_connection_ok_button</action-widget>
|
||||||
</action-widgets>
|
</action-widgets>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkDialog" id="update_modes_dialog">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="title" translatable="yes">Update ADIF Modes</property>
|
||||||
|
<property name="destroy_with_parent">True</property>
|
||||||
|
<property name="type_hint">dialog</property>
|
||||||
|
<property name="transient_for">pyqso</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">2</property>
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<object class="GtkButtonBox">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="update_modes_cancel_button">
|
||||||
|
<property name="label">gtk-cancel</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="always_show_image">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="update_modes_ok_button">
|
||||||
|
<property name="label">gtk-ok</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="always_show_image">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="adif_url_hbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="adif_url_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">URL of ADIF webpage</property>
|
||||||
|
<property name="width_chars">12</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">2</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="adif_url_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<action-widgets>
|
||||||
|
<action-widget response="-6">update_modes_cancel_button</action-widget>
|
||||||
|
<action-widget response="-5">update_modes_ok_button</action-widget>
|
||||||
|
</action-widgets>
|
||||||
|
</object>
|
||||||
<object class="GtkMenu" id="popup">
|
<object class="GtkMenu" id="popup">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright (C) 2019 Christian Thomas Jacobs.
|
||||||
|
|
||||||
|
# This file is part of PyQSO.
|
||||||
|
|
||||||
|
# PyQSO is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# PyQSO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with PyQSO. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateModesDialog:
|
||||||
|
|
||||||
|
""" A handler for the Gtk.Dialog through which a user can specify a URL to an ADIF specification. """
|
||||||
|
|
||||||
|
def __init__(self, application):
|
||||||
|
""" Create and show the dialog to the user.
|
||||||
|
|
||||||
|
:arg application: The PyQSO application containing the main Gtk window, etc.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.builder = application.builder
|
||||||
|
glade_file_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), "res", "pyqso.glade")
|
||||||
|
self.builder.add_objects_from_file(glade_file_path, ("update_modes_dialog",))
|
||||||
|
self.dialog = self.builder.get_object("update_modes_dialog")
|
||||||
|
self.sources = {"URL": self.builder.get_object("adif_url_entry")}
|
||||||
|
|
||||||
|
self.dialog.show_all()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
""" Return the URL of the ADIF specification's webpage.
|
||||||
|
|
||||||
|
:returns: The URL of the ADIF specification's webpage.
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return self.sources["URL"].get_text()
|
||||||
|
|
Ładowanie…
Reference in New Issue