kopia lustrzana https://github.com/ctjacobs/pyqso
Make the code pep8 compliant, using the autopep8 tool. Note that we are ignoring the following: E501,F403,E226,E402,W503.
rodzic
1e5a657ca7
commit
c993704e84
|
@ -41,7 +41,9 @@ from pyqso.toolbar import *
|
|||
from pyqso.toolbox import *
|
||||
from pyqso.preferences_dialog import *
|
||||
|
||||
|
||||
class PyQSO(Gtk.Window):
|
||||
|
||||
""" The PyQSO application class. """
|
||||
|
||||
def __init__(self, logbook_path=None):
|
||||
|
@ -180,4 +182,3 @@ if(__name__ == "__main__"):
|
|||
signal.signal(signal.SIGINT, signal.SIG_DFL) # Exit PyQSO if a SIGINT signal is captured.
|
||||
application = PyQSO(args.logbook) # Populate the main window and show it
|
||||
Gtk.main() # Start up the event loop!
|
||||
|
||||
|
|
226
pyqso/adif.py
226
pyqso/adif.py
|
@ -53,27 +53,27 @@ AVAILABLE_FIELD_NAMES_ORDERED = ["CALL", "QSO_DATE", "TIME_ON", "FREQ", "BAND",
|
|||
"RST_SENT", "RST_RCVD", "QSL_SENT", "QSL_RCVD", "NOTES", "NAME",
|
||||
"ADDRESS", "STATE", "COUNTRY", "DXCC", "CQZ", "ITUZ", "IOTA"]
|
||||
# Define the more user-friendly versions of the field names.
|
||||
AVAILABLE_FIELD_NAMES_FRIENDLY = {"CALL":"Callsign",
|
||||
"QSO_DATE":"Date",
|
||||
"TIME_ON":"Time",
|
||||
"FREQ":"Frequency (MHz)",
|
||||
"BAND":"Band",
|
||||
"MODE":"Mode",
|
||||
"SUBMODE":"Submode",
|
||||
"TX_PWR":"TX Power (W)",
|
||||
"RST_SENT":"RST Sent",
|
||||
"RST_RCVD":"RST Received",
|
||||
"QSL_SENT":"QSL Sent",
|
||||
"QSL_RCVD":"QSL Received",
|
||||
"NOTES":"Notes",
|
||||
"NAME":"Name",
|
||||
"ADDRESS":"Address",
|
||||
"STATE":"State",
|
||||
"COUNTRY":"Country",
|
||||
"DXCC":"DXCC",
|
||||
"CQZ":"CQ Zone",
|
||||
"ITUZ":"ITU Zone",
|
||||
"IOTA":"IOTA Designator"}
|
||||
AVAILABLE_FIELD_NAMES_FRIENDLY = {"CALL": "Callsign",
|
||||
"QSO_DATE": "Date",
|
||||
"TIME_ON": "Time",
|
||||
"FREQ": "Frequency (MHz)",
|
||||
"BAND": "Band",
|
||||
"MODE": "Mode",
|
||||
"SUBMODE": "Submode",
|
||||
"TX_PWR": "TX Power (W)",
|
||||
"RST_SENT": "RST Sent",
|
||||
"RST_RCVD": "RST Received",
|
||||
"QSL_SENT": "QSL Sent",
|
||||
"QSL_RCVD": "QSL Received",
|
||||
"NOTES": "Notes",
|
||||
"NAME": "Name",
|
||||
"ADDRESS": "Address",
|
||||
"STATE": "State",
|
||||
"COUNTRY": "Country",
|
||||
"DXCC": "DXCC",
|
||||
"CQZ": "CQ Zone",
|
||||
"ITUZ": "ITU Zone",
|
||||
"IOTA": "IOTA Designator"}
|
||||
|
||||
# A: AwardList
|
||||
# B: Boolean
|
||||
|
@ -88,91 +88,91 @@ AVAILABLE_FIELD_NAMES_FRIENDLY = {"CALL":"Callsign",
|
|||
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":("",),
|
||||
"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":("",)
|
||||
MODES = {"": ("",),
|
||||
"AM": ("",),
|
||||
"ATV": ("",),
|
||||
"CHIP": ("", "CHIP64", "CHIP128"),
|
||||
"CLO": ("",),
|
||||
"CONTESTI": ("",),
|
||||
"CW": ("", "PCW"),
|
||||
"DIGITALVOICE": ("",),
|
||||
"DOMINO": ("", "DOMINOEX", "DOMINOF"),
|
||||
"DSTAR": ("",),
|
||||
"FAX": ("",),
|
||||
"FM": ("",),
|
||||
"FSK441": ("",),
|
||||
"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":("",)
|
||||
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.
|
||||
|
@ -185,7 +185,9 @@ BANDS_RANGES = [(None, None), (0.136, 0.137), (0.472, 0.479), (0.501, 0.504), (1
|
|||
|
||||
ADIF_VERSION = "3.0.4"
|
||||
|
||||
|
||||
class ADIF:
|
||||
|
||||
""" The ADIF class supplies methods for reading, parsing, and writing log files in the Amateur Data Interchange Format (ADIF).
|
||||
For more information, visit http://adif.org/ """
|
||||
|
||||
|
@ -351,7 +353,7 @@ class ADIF:
|
|||
# Only write out the fields that exist and that have some data in them.
|
||||
continue
|
||||
else:
|
||||
if( (r[field_name] != "NULL") and (r[field_name] != "") ):
|
||||
if((r[field_name] != "NULL") and (r[field_name] != "")):
|
||||
f.write("<%s:%d>%s\n" % (field_name.lower(), len(r[field_name]), r[field_name]))
|
||||
f.write("<eor>\n")
|
||||
|
||||
|
@ -366,7 +368,6 @@ class ADIF:
|
|||
|
||||
return
|
||||
|
||||
|
||||
def is_valid(self, field_name, data, data_type):
|
||||
""" Validate the data in a field with respect to the ADIF specification.
|
||||
|
||||
|
@ -456,7 +457,7 @@ class ADIF:
|
|||
# otherwise there may be an invalid character after the match.
|
||||
return (len(data) == 6) # HHMMSS format
|
||||
|
||||
#FIXME: Need to make sure that the "S" and "M" data types accept ASCII-only characters
|
||||
# FIXME: Need to make sure that the "S" and "M" data types accept ASCII-only characters
|
||||
# in the range 32-126 inclusive.
|
||||
elif(data_type == "S"):
|
||||
# String
|
||||
|
@ -484,10 +485,10 @@ class ADIF:
|
|||
|
||||
elif(data_type == "M"):
|
||||
# MultilineString
|
||||
#m = re.match(r"(.+(\r\n)*.*)", data)
|
||||
#if(m is None):
|
||||
# m = re.match(r"(.+(\r\n)*.*)", data)
|
||||
# if(m is None):
|
||||
# return False
|
||||
#else:
|
||||
# else:
|
||||
# return (m.group(0) == data)
|
||||
return True
|
||||
|
||||
|
@ -515,7 +516,6 @@ class ADIF:
|
|||
# otherwise there may be an invalid character after the match.
|
||||
return (len(data) == 10)
|
||||
|
||||
|
||||
elif(data_type == "E" or data_type == "A"):
|
||||
# Enumeration, AwardList.
|
||||
if(field_name == "MODE"):
|
||||
|
@ -530,6 +530,7 @@ class ADIF:
|
|||
|
||||
|
||||
class TestADIF(unittest.TestCase):
|
||||
|
||||
""" The unit tests for the ADIF module. """
|
||||
|
||||
def setUp(self):
|
||||
|
@ -635,8 +636,8 @@ class TestADIF(unittest.TestCase):
|
|||
|
||||
def test_adif_write(self):
|
||||
""" Check that records can be written to an ADIF file correctly. """
|
||||
records = [{"CALL":"TEST123", "QSO_DATE":"20120402", "TIME_ON":"1234", "FREQ":"145.500", "BAND":"2m", "MODE":"FM", "RST_SENT":"59", "RST_RCVD":"59"},
|
||||
{"CALL":"TEST123", "QSO_DATE":"20130312", "TIME_ON":"0101", "FREQ":"145.750", "BAND":"2m", "MODE":"FM"}]
|
||||
records = [{"CALL": "TEST123", "QSO_DATE": "20120402", "TIME_ON": "1234", "FREQ": "145.500", "BAND": "2m", "MODE": "FM", "RST_SENT": "59", "RST_RCVD": "59"},
|
||||
{"CALL": "TEST123", "QSO_DATE": "20130312", "TIME_ON": "0101", "FREQ": "145.750", "BAND": "2m", "MODE": "FM"}]
|
||||
self.adif.write(records, "ADIF.test_write.adi")
|
||||
|
||||
f = open("ADIF.test_write.adi", 'r')
|
||||
|
@ -718,4 +719,3 @@ class TestADIF(unittest.TestCase):
|
|||
|
||||
if(__name__ == '__main__'):
|
||||
unittest.main()
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
from gi.repository import Gtk
|
||||
import logging
|
||||
|
||||
|
||||
def error(parent, message):
|
||||
""" Display an error message.
|
||||
|
||||
|
@ -29,6 +30,7 @@ def error(parent, message):
|
|||
logging.error(message)
|
||||
_handle_gtk_dialog(parent, Gtk.MessageType.ERROR, message, "Error")
|
||||
|
||||
|
||||
def info(parent, message):
|
||||
""" Display some information.
|
||||
|
||||
|
@ -38,6 +40,7 @@ def info(parent, message):
|
|||
logging.debug(message)
|
||||
_handle_gtk_dialog(parent, Gtk.MessageType.INFO, message, "Information")
|
||||
|
||||
|
||||
def question(parent, message):
|
||||
""" Ask the user a question. The dialog comes with 'Yes' and 'No' response buttons.
|
||||
|
||||
|
@ -48,6 +51,7 @@ def question(parent, message):
|
|||
"""
|
||||
return _handle_gtk_dialog(parent, Gtk.MessageType.QUESTION, message, "Question")
|
||||
|
||||
|
||||
def _handle_gtk_dialog(parent, msgtype, message, title):
|
||||
"""
|
||||
Instantiate and present a dialog to the user.
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
from gi.repository import Gtk
|
||||
import logging
|
||||
|
||||
|
||||
class Awards(Gtk.VBox):
|
||||
|
||||
""" A tool for tracking progress towards an award. Currently this only supports the DXCC award.
|
||||
For more information visit http://www.arrl.org/dxcc """
|
||||
|
||||
|
@ -29,7 +31,7 @@ class Awards(Gtk.VBox):
|
|||
|
||||
:arg parent: The parent Gtk window.
|
||||
"""
|
||||
#TODO: This only considers the DXCC award for now.
|
||||
# TODO: This only considers the DXCC award for now.
|
||||
logging.debug("New Awards instance created!")
|
||||
|
||||
Gtk.VBox.__init__(self, spacing=2)
|
||||
|
@ -96,7 +98,7 @@ class Awards(Gtk.VBox):
|
|||
elif(r["MODE"].upper() == "CW"):
|
||||
count[1][band] += 1
|
||||
else:
|
||||
#FIXME: This assumes that all the other modes in the ADIF list are digital modes. Is this the case?
|
||||
# FIXME: This assumes that all the other modes in the ADIF list are digital modes. Is this the case?
|
||||
count[2][band] += 1
|
||||
count[3][band] += 1 # Keep the total of each column in the "Mixed" mode
|
||||
else:
|
||||
|
@ -106,4 +108,3 @@ class Awards(Gtk.VBox):
|
|||
self.awards.append([self.modes[i]] + count[i])
|
||||
logging.debug("Awards table updated.")
|
||||
return
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ from xml.dom import minidom
|
|||
|
||||
from pyqso.auxiliary_dialogs import *
|
||||
|
||||
|
||||
class CallsignLookupQRZ():
|
||||
|
||||
""" Use qrz.com to lookup details about a particular callsign. """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -74,7 +76,7 @@ class CallsignLookupQRZ():
|
|||
|
||||
return connected
|
||||
|
||||
def lookup(self, full_callsign, ignore_prefix_suffix = True):
|
||||
def lookup(self, full_callsign, ignore_prefix_suffix=True):
|
||||
""" Parse the XML tree that is returned from the qrz.com XML server to obtain the NAME, ADDRESS, STATE, COUNTRY, DXCC, CQZ, ITUZ, and IOTA field data (if present).
|
||||
|
||||
:arg str full_callsign: The callsign to look up (without any prefix/suffix stripping).
|
||||
|
@ -92,7 +94,7 @@ class CallsignLookupQRZ():
|
|||
callsign = full_callsign
|
||||
|
||||
# Commence lookup.
|
||||
fields_and_data = {"NAME":"", "ADDRESS":"", "STATE":"", "COUNTRY":"", "DXCC":"", "CQZ":"", "ITUZ":"", "IOTA":""}
|
||||
fields_and_data = {"NAME": "", "ADDRESS": "", "STATE": "", "COUNTRY": "", "DXCC": "", "CQZ": "", "ITUZ": "", "IOTA": ""}
|
||||
if(self.session_key):
|
||||
request = '/xml/current/?s=%s;callsign=%s' % (self.session_key, callsign)
|
||||
self.connection.request('GET', request)
|
||||
|
@ -154,6 +156,7 @@ class CallsignLookupQRZ():
|
|||
|
||||
|
||||
class CallsignLookupHamQTH():
|
||||
|
||||
""" Use hamqth.com to lookup details about a particular callsign. """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -199,7 +202,7 @@ class CallsignLookupHamQTH():
|
|||
|
||||
return connected
|
||||
|
||||
def lookup(self, full_callsign, ignore_prefix_suffix = True):
|
||||
def lookup(self, full_callsign, ignore_prefix_suffix=True):
|
||||
""" Parse the XML tree that is returned from the hamqth.com XML server to obtain the NAME, ADDRESS, STATE, COUNTRY, DXCC, CQZ, ITUZ, and IOTA field data (if present),
|
||||
|
||||
:arg str full_callsign: The callsign to look up (without any prefix/suffix stripping).
|
||||
|
@ -217,7 +220,7 @@ class CallsignLookupHamQTH():
|
|||
callsign = full_callsign
|
||||
|
||||
# Commence lookup.
|
||||
fields_and_data = {"NAME":"", "ADDRESS":"", "STATE":"", "COUNTRY":"", "DXCC":"", "CQZ":"", "ITUZ":"", "IOTA":""}
|
||||
fields_and_data = {"NAME": "", "ADDRESS": "", "STATE": "", "COUNTRY": "", "DXCC": "", "CQZ": "", "ITUZ": "", "IOTA": ""}
|
||||
if(self.session_id):
|
||||
request = '/xml.php?id=%s&callsign=%s&prg=pyqso' % (self.session_id, callsign)
|
||||
self.connection.request('GET', request)
|
||||
|
@ -307,7 +310,9 @@ def strip(full_callsign):
|
|||
callsign = full_callsign
|
||||
return callsign
|
||||
|
||||
|
||||
class TestCallsignLookup(unittest.TestCase):
|
||||
|
||||
""" The unit tests for the CallsignLookup class. """
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -29,7 +29,9 @@ from pyqso.telnet_connection_dialog import *
|
|||
|
||||
BOOKMARKS_FILE = os.path.expanduser('~/.config/pyqso/bookmarks.ini')
|
||||
|
||||
|
||||
class DXCluster(Gtk.VBox):
|
||||
|
||||
""" A tool for connecting to a DX cluster (specifically Telnet-based DX clusters). """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -48,7 +50,7 @@ class DXCluster(Gtk.VBox):
|
|||
|
||||
self.items = {}
|
||||
|
||||
###### CONNECTION ######
|
||||
# CONNECTION ######
|
||||
mitem_connection = Gtk.MenuItem(label="Connection")
|
||||
self.menubar.append(mitem_connection)
|
||||
subm_connection = Gtk.Menu()
|
||||
|
@ -64,12 +66,12 @@ class DXCluster(Gtk.VBox):
|
|||
|
||||
subm_connect = Gtk.Menu()
|
||||
|
||||
## New
|
||||
# New
|
||||
mitem_new = Gtk.MenuItem(label="New...")
|
||||
mitem_new.connect("activate", self.new_server)
|
||||
subm_connect.append(mitem_new)
|
||||
|
||||
## From Bookmark
|
||||
# From Bookmark
|
||||
mitem_bookmark = Gtk.MenuItem(label="From Bookmark")
|
||||
self.subm_bookmarks = Gtk.Menu()
|
||||
mitem_bookmark.set_submenu(self.subm_bookmarks)
|
||||
|
@ -325,7 +327,9 @@ class DXCluster(Gtk.VBox):
|
|||
self.send.set_sensitive(not sensitive)
|
||||
return
|
||||
|
||||
|
||||
class TestDXCluster(unittest.TestCase):
|
||||
|
||||
""" The unit tests for the DXCluster class. """
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -36,7 +36,9 @@ except ImportError as e:
|
|||
logging.warning("Could not import a non-standard Python module needed by the GreyLine class, or the version of the non-standard module is too old. Check that all the PyQSO dependencies are satisfied.")
|
||||
have_necessary_modules = False
|
||||
|
||||
|
||||
class GreyLine(Gtk.VBox):
|
||||
|
||||
""" A tool for visualising the grey line. """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -91,4 +93,3 @@ class GreyLine(Gtk.VBox):
|
|||
return True
|
||||
else:
|
||||
return False # Don't try to re-draw the canvas if the necessary modules to do so could not be imported.
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ import unittest
|
|||
from pyqso.adif import AVAILABLE_FIELD_NAMES_ORDERED
|
||||
from pyqso.record_dialog import *
|
||||
|
||||
|
||||
class Log(Gtk.ListStore):
|
||||
|
||||
""" A single log inside of the whole logbook. A Log object can store multiple Record objects. """
|
||||
|
||||
def __init__(self, connection, name):
|
||||
|
@ -141,7 +143,7 @@ class Log(Gtk.ListStore):
|
|||
database_entry = []
|
||||
for t in column_names:
|
||||
column_name = str(t[1]) # 't' here is a tuple
|
||||
if( (column_name.upper() in AVAILABLE_FIELD_NAMES_ORDERED) and (column_name.upper() in list(fields_and_data[r].keys())) ):
|
||||
if((column_name.upper() in AVAILABLE_FIELD_NAMES_ORDERED) and (column_name.upper() in list(fields_and_data[r].keys()))):
|
||||
database_entry.append(fields_and_data[r][column_name.upper()])
|
||||
else:
|
||||
if(column_name != "id"): # Ignore the row index field. This is a special case since it's not in AVAILABLE_FIELD_NAMES_ORDERED.
|
||||
|
@ -309,6 +311,7 @@ class Log(Gtk.ListStore):
|
|||
logging.exception(e)
|
||||
return None
|
||||
|
||||
|
||||
class TestLog(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -316,7 +319,7 @@ class TestLog(unittest.TestCase):
|
|||
self.connection.row_factory = sqlite.Row
|
||||
|
||||
self.field_names = ["CALL", "QSO_DATE", "TIME_ON", "FREQ", "BAND", "MODE", "RST_SENT", "RST_RCVD"]
|
||||
self.fields_and_data = {"CALL":"TEST123", "QSO_DATE":"20130312", "TIME_ON":"1234", "FREQ":"145.500", "BAND":"2m", "MODE":"FM", "RST_SENT":"59", "RST_RCVD":"59"}
|
||||
self.fields_and_data = {"CALL": "TEST123", "QSO_DATE": "20130312", "TIME_ON": "1234", "FREQ": "145.500", "BAND": "2m", "MODE": "FM", "RST_SENT": "59", "RST_RCVD": "59"}
|
||||
|
||||
c = self.connection.cursor()
|
||||
query = "CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT"
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
from gi.repository import Gtk
|
||||
import logging
|
||||
|
||||
|
||||
class LogNameDialog(Gtk.Dialog):
|
||||
|
||||
""" A Gtk.Dialog where a user can specify the name of a Log object. """
|
||||
|
||||
def __init__(self, parent, title=None, name=None):
|
||||
|
@ -62,5 +64,3 @@ class LogNameDialog(Gtk.Dialog):
|
|||
|
||||
logging.debug("Retrieving the log name from the LogNameDialog...")
|
||||
return self.entry.get_text()
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,9 @@ from pyqso.log import *
|
|||
from pyqso.log_name_dialog import *
|
||||
from pyqso.auxiliary_dialogs import *
|
||||
|
||||
|
||||
class Logbook(Gtk.Notebook):
|
||||
|
||||
""" A Logbook object can store multiple Log objects. """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -127,7 +129,7 @@ class Logbook(Gtk.Notebook):
|
|||
self.logs.append(l)
|
||||
except (sqlite.Error, IndexError) as e:
|
||||
logging.exception(e)
|
||||
error(parent = self.parent, message = "Oops! Something went wrong when trying to retrieve the logs from the logbook. Perhaps the logbook file is encrypted, corrupted, or in the wrong format?")
|
||||
error(parent=self.parent, message="Oops! Something went wrong when trying to retrieve the logs from the logbook. Perhaps the logbook file is encrypted, corrupted, or in the wrong format?")
|
||||
return
|
||||
|
||||
logging.debug("All logs retrieved successfully. Now attempting to render them all in the Gtk.Notebook...")
|
||||
|
@ -312,7 +314,7 @@ class Logbook(Gtk.Notebook):
|
|||
|
||||
self.summary["YEARLY_STATISTICS"] = Figure()
|
||||
canvas = FigureCanvas(self.summary["YEARLY_STATISTICS"])
|
||||
canvas.set_size_request(400,400)
|
||||
canvas.set_size_request(400, 400)
|
||||
canvas.show()
|
||||
vbox.pack_start(canvas, True, True, 4)
|
||||
|
||||
|
@ -814,7 +816,8 @@ class Logbook(Gtk.Notebook):
|
|||
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
|
||||
filter = Gtk.FileFilter()
|
||||
filter.set_name("All ADIF files (*.adi, *.ADI)")
|
||||
filter.add_pattern("*.adi"); filter.add_pattern("*.ADI")
|
||||
filter.add_pattern("*.adi")
|
||||
filter.add_pattern("*.ADI")
|
||||
dialog.add_filter(filter)
|
||||
|
||||
filter = Gtk.FileFilter()
|
||||
|
@ -907,7 +910,8 @@ class Logbook(Gtk.Notebook):
|
|||
|
||||
filter = Gtk.FileFilter()
|
||||
filter.set_name("All ADIF files (*.adi, *.ADI)")
|
||||
filter.add_pattern("*.adi"); filter.add_pattern("*.ADI")
|
||||
filter.add_pattern("*.adi")
|
||||
filter.add_pattern("*.ADI")
|
||||
dialog.add_filter(filter)
|
||||
|
||||
filter = Gtk.FileFilter()
|
||||
|
@ -1099,12 +1103,12 @@ class Logbook(Gtk.Notebook):
|
|||
filter_iter = self.sorter[log_index].convert_iter_to_child_iter(sort_iter)
|
||||
# ...and the ListStore model (i.e. the log) is a child of the filter model.
|
||||
child_iter = self.filter[log_index].convert_iter_to_child_iter(filter_iter)
|
||||
row_index = log.get_value(child_iter,0)
|
||||
row_index = log.get_value(child_iter, 0)
|
||||
except IndexError:
|
||||
logging.debug("Trying to delete a record, but there are no records in the log!")
|
||||
return
|
||||
|
||||
response = question(parent=self.parent, message = "Are you sure you want to delete record %d?" % row_index)
|
||||
response = question(parent=self.parent, message="Are you sure you want to delete record %d?" % row_index)
|
||||
if(response == Gtk.ResponseType.YES):
|
||||
# Deletes the record with index 'row_index' from the Records list.
|
||||
# 'iter' is needed to remove the record from the ListStore itself.
|
||||
|
@ -1135,7 +1139,7 @@ class Logbook(Gtk.Notebook):
|
|||
filter_iter = self.sorter[log_index].convert_iter_to_child_iter(sort_iter)
|
||||
# ...and the ListStore model (i.e. the log) is a child of the filter model.
|
||||
child_iter = self.filter[log_index].convert_iter_to_child_iter(filter_iter)
|
||||
row_index = log.get_value(child_iter,0)
|
||||
row_index = log.get_value(child_iter, 0)
|
||||
except IndexError:
|
||||
logging.debug("Could not find the selected row's index!")
|
||||
return
|
||||
|
@ -1257,7 +1261,9 @@ class Logbook(Gtk.Notebook):
|
|||
break
|
||||
return log_index
|
||||
|
||||
|
||||
class TestLogbook(unittest.TestCase):
|
||||
|
||||
""" The unit tests for the Logbook class. """
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -22,7 +22,9 @@ import logging
|
|||
import configparser
|
||||
import os.path
|
||||
|
||||
|
||||
class Menu(Gtk.MenuBar):
|
||||
|
||||
""" The PyQSO menu bar along the top of the main window. """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -42,7 +44,7 @@ class Menu(Gtk.MenuBar):
|
|||
|
||||
self.items = {}
|
||||
|
||||
###### LOGBOOK ######
|
||||
# LOGBOOK ######
|
||||
mitem_logbook = Gtk.MenuItem("Logbook")
|
||||
self.append(mitem_logbook)
|
||||
subm_logbook = Gtk.Menu()
|
||||
|
@ -156,8 +158,7 @@ class Menu(Gtk.MenuBar):
|
|||
subm_logbook.append(mitem_quit)
|
||||
self.items["QUIT"] = mitem_quit
|
||||
|
||||
|
||||
###### RECORDS ######
|
||||
# RECORDS ######
|
||||
mitem_records = Gtk.MenuItem("Records")
|
||||
self.append(mitem_records)
|
||||
subm_records = Gtk.Menu()
|
||||
|
@ -201,8 +202,7 @@ class Menu(Gtk.MenuBar):
|
|||
subm_records.append(mitem_removeduplicates)
|
||||
self.items["REMOVE_DUPLICATES"] = mitem_removeduplicates
|
||||
|
||||
|
||||
###### VIEW ######
|
||||
# VIEW ######
|
||||
mitem_view = Gtk.MenuItem("View")
|
||||
self.append(mitem_view)
|
||||
subm_view = Gtk.Menu()
|
||||
|
@ -228,8 +228,7 @@ class Menu(Gtk.MenuBar):
|
|||
subm_view.append(mitem_preferences)
|
||||
self.items["PREFERENCES"] = mitem_preferences
|
||||
|
||||
|
||||
###### HELP ######
|
||||
# HELP ######
|
||||
mitem_help = Gtk.MenuItem("Help")
|
||||
self.append(mitem_help)
|
||||
subm_help = Gtk.Menu()
|
||||
|
@ -284,4 +283,3 @@ class Menu(Gtk.MenuBar):
|
|||
self.items[item_name].set_sensitive(sensitive)
|
||||
logging.debug("Set record-related menu item sensitivity to: %s." % sensitive)
|
||||
return
|
||||
|
||||
|
|
|
@ -33,7 +33,9 @@ from pyqso.adif import *
|
|||
|
||||
PREFERENCES_FILE = os.path.expanduser("~/.config/pyqso/preferences.ini")
|
||||
|
||||
|
||||
class PreferencesDialog(Gtk.Dialog):
|
||||
|
||||
""" A dialog to specify the PyQSO preferences. """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -110,7 +112,9 @@ class PreferencesDialog(Gtk.Dialog):
|
|||
|
||||
return
|
||||
|
||||
|
||||
class GeneralPage(Gtk.VBox):
|
||||
|
||||
""" The section of the preferences dialog containing general preferences. """
|
||||
|
||||
def __init__(self):
|
||||
|
@ -187,7 +191,9 @@ class GeneralPage(Gtk.VBox):
|
|||
data["KEEP_OPEN"] = self.sources["KEEP_OPEN"].get_active()
|
||||
return data
|
||||
|
||||
|
||||
class ViewPage(Gtk.VBox):
|
||||
|
||||
""" The section of the preferences dialog containing view-related preferences. """
|
||||
|
||||
def __init__(self):
|
||||
|
@ -208,14 +214,14 @@ class ViewPage(Gtk.VBox):
|
|||
# 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
|
||||
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 ])
|
||||
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:
|
||||
|
@ -239,7 +245,9 @@ class ViewPage(Gtk.VBox):
|
|||
data[field_name] = self.sources[field_name].get_active()
|
||||
return data
|
||||
|
||||
|
||||
class HamlibPage(Gtk.VBox):
|
||||
|
||||
""" The section of the preferences dialog containing Hamlib-related preferences. """
|
||||
|
||||
def __init__(self):
|
||||
|
@ -321,7 +329,9 @@ class HamlibPage(Gtk.VBox):
|
|||
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):
|
||||
|
@ -359,8 +369,7 @@ class RecordsPage(Gtk.VBox):
|
|||
frame.add(vbox)
|
||||
self.pack_start(frame, False, False, 2)
|
||||
|
||||
|
||||
## Default values frame
|
||||
# Default values frame
|
||||
frame = Gtk.Frame()
|
||||
frame.set_label("Default values")
|
||||
vbox = Gtk.VBox()
|
||||
|
@ -423,7 +432,6 @@ class RecordsPage(Gtk.VBox):
|
|||
frame.add(vbox)
|
||||
self.pack_start(frame, False, False, 2)
|
||||
|
||||
|
||||
# Callsign lookup frame
|
||||
frame = Gtk.Frame()
|
||||
frame.set_label("Callsign lookup")
|
||||
|
@ -523,7 +531,9 @@ class RecordsPage(Gtk.VBox):
|
|||
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):
|
||||
|
@ -561,4 +571,3 @@ class ADIFPage(Gtk.VBox):
|
|||
data = {}
|
||||
data["MERGE_COMMENT"] = self.sources["MERGE_COMMENT"].get_active()
|
||||
return data
|
||||
|
||||
|
|
|
@ -34,7 +34,9 @@ from pyqso.adif import *
|
|||
from pyqso.callsign_lookup import *
|
||||
from pyqso.auxiliary_dialogs import *
|
||||
|
||||
|
||||
class RecordDialog(Gtk.Dialog):
|
||||
|
||||
""" A dialog through which users can enter information about a QSO/record. """
|
||||
|
||||
def __init__(self, parent, log, index=None):
|
||||
|
@ -57,7 +59,7 @@ class RecordDialog(Gtk.Dialog):
|
|||
config = configparser.ConfigParser()
|
||||
have_config = (config.read(expanduser('~/.config/pyqso/preferences.ini')) != [])
|
||||
|
||||
## QSO DATA FRAME
|
||||
# QSO DATA FRAME
|
||||
qso_frame = Gtk.Frame()
|
||||
qso_frame.set_label("QSO Information")
|
||||
self.vbox.add(qso_frame)
|
||||
|
@ -259,8 +261,7 @@ class RecordDialog(Gtk.Dialog):
|
|||
|
||||
qso_frame.add(hbox_inner)
|
||||
|
||||
|
||||
## STATION INFORMATION FRAME
|
||||
# STATION INFORMATION FRAME
|
||||
station_frame = Gtk.Frame()
|
||||
station_frame.set_label("Station Information")
|
||||
self.vbox.add(station_frame)
|
||||
|
@ -396,7 +397,7 @@ class RecordDialog(Gtk.Dialog):
|
|||
# Automatically fill in the current date and time
|
||||
self.set_current_datetime_callback()
|
||||
|
||||
## Set up default field values
|
||||
# Set up default field values
|
||||
# Mode
|
||||
(section, option) = ("records", "default_mode")
|
||||
if(have_config and config.has_option(section, option)):
|
||||
|
@ -511,7 +512,6 @@ class RecordDialog(Gtk.Dialog):
|
|||
self.sources["BAND"].set_active(0) # If we've reached this, then the frequency does not lie in any of the specified bands.
|
||||
return
|
||||
|
||||
|
||||
def lookup_callback(self, widget=None):
|
||||
""" Get the callsign-related data from an online database and store it in the relevant Gtk.Entry boxes, but return None. """
|
||||
|
||||
|
@ -532,10 +532,10 @@ class RecordDialog(Gtk.Dialog):
|
|||
try:
|
||||
if(database == "qrz.com"):
|
||||
# QRZ.com
|
||||
callsign_lookup = CallsignLookupQRZ(parent = self)
|
||||
callsign_lookup = CallsignLookupQRZ(parent=self)
|
||||
elif(database == "hamqth.com"):
|
||||
# HamQTH
|
||||
callsign_lookup = CallsignLookupHamQTH(parent = self)
|
||||
callsign_lookup = CallsignLookupHamQTH(parent=self)
|
||||
else:
|
||||
raise ValueError("Unknown callsign database: %s" % database)
|
||||
except ValueError as e:
|
||||
|
@ -575,7 +575,7 @@ class RecordDialog(Gtk.Dialog):
|
|||
|
||||
def calendar_callback(self, widget):
|
||||
""" Open up a calendar widget for easy QSO_DATE selection. Return None after the user destroys the dialog. """
|
||||
calendar = CalendarDialog(parent = self)
|
||||
calendar = CalendarDialog(parent=self)
|
||||
response = calendar.run()
|
||||
if(response == Gtk.ResponseType.OK):
|
||||
date = calendar.get_date()
|
||||
|
@ -606,7 +606,9 @@ class RecordDialog(Gtk.Dialog):
|
|||
|
||||
return
|
||||
|
||||
|
||||
class CalendarDialog(Gtk.Dialog):
|
||||
|
||||
""" A simple dialog containing a Gtk.Calendar widget. Using this ensures the date is in the correct YYYYMMDD format required by ADIF. """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -639,4 +641,3 @@ class CalendarDialog(Gtk.Dialog):
|
|||
day = "0" + str(day)
|
||||
date = str(year) + str(month) + str(day)
|
||||
return date
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
from gi.repository import Gtk
|
||||
import logging
|
||||
|
||||
|
||||
class TelnetConnectionDialog(Gtk.Dialog):
|
||||
|
||||
""" A simple dialog through which users can specify host and login information for a Telnet server.
|
||||
This can be used to connect to DX clusters. """
|
||||
|
||||
|
@ -89,4 +91,3 @@ class TelnetConnectionDialog(Gtk.Dialog):
|
|||
"""
|
||||
logging.debug("Returning Telnet connection information...")
|
||||
return self.sources
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
from gi.repository import Gtk
|
||||
import logging
|
||||
|
||||
|
||||
class Toolbar(Gtk.HBox):
|
||||
|
||||
""" The toolbar underneath the menu bar. """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -135,6 +137,3 @@ class Toolbar(Gtk.HBox):
|
|||
self.buttons[button_name].set_sensitive(sensitive)
|
||||
logging.debug("Set record-related toolbar item sensitivity to: %s." % sensitive)
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@ from pyqso.dx_cluster import *
|
|||
from pyqso.grey_line import *
|
||||
from pyqso.awards import *
|
||||
|
||||
|
||||
class Toolbox(Gtk.Frame):
|
||||
|
||||
""" Contains a Gtk.Notebook full of amateur radio-related tools. """
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -59,7 +61,6 @@ class Toolbox(Gtk.Frame):
|
|||
|
||||
def _on_switch_page(self, widget, label, new_page):
|
||||
""" Re-draw the Grey Line if the user switches to the grey line tab. """
|
||||
if(type(label) == GreyLine):
|
||||
if(isinstance(label, GreyLine)):
|
||||
label.draw() # Note that 'label' is actually a GreyLine object.
|
||||
return
|
||||
|
||||
|
|
3
setup.py
3
setup.py
|
@ -26,7 +26,7 @@ setup(name='PyQSO',
|
|||
author_email='c.jacobs10@imperial.ac.uk',
|
||||
url='https://github.com/ctjacobs/pyqso',
|
||||
packages=['pyqso'],
|
||||
package_dir = {'pyqso': 'pyqso'},
|
||||
package_dir={'pyqso': 'pyqso'},
|
||||
scripts=["bin/pyqso"],
|
||||
data_files=[("icons", ["icons/log_64x64.png"])],
|
||||
classifiers=[
|
||||
|
@ -38,4 +38,3 @@ setup(name='PyQSO',
|
|||
'Topic :: Communications :: Ham Radio',
|
||||
]
|
||||
)
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue