Improved docstrings.

pull/34/merge
Christian Jacobs 2015-10-03 17:51:25 +01:00
rodzic bf26af984d
commit 45abb28e38
16 zmienionych plików z 394 dodań i 84 usunięć

Wyświetl plik

@ -44,9 +44,12 @@ from pyqso.preferences_dialog import *
class PyQSO(Gtk.Window):
""" The PyQSO application class. """
def __init__(self, logbook_path):
""" Set up the main (root) window, start the event loop, and open a logbook (if the logbook's path is specified by the user in the command line). """
def __init__(self, logbook_path=None):
""" Set up the main (root) window, start the event loop, and open a logbook (if the logbook's path is specified by the user in the command line).
:arg str logbook_path: An optional argument containing the path of the logbook file to open. If no value is provided, this defaults to None and no logbook is opened.
"""
# Call the constructor of the super class (Gtk.Window)
Gtk.Window.__init__(self, title="PyQSO")
@ -109,7 +112,7 @@ class PyQSO(Gtk.Window):
return
def show_about(self, widget):
""" Show the About dialog, which includes license information. This method returns None after the user destroys the dialog. """
""" Show the About dialog, which includes license information. """
about = Gtk.AboutDialog()
about.set_modal(True)
about.set_transient_for(parent=self)
@ -140,7 +143,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.""")
return
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. This method returns None after the user destroys the dialog. """
""" 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()
if(response == Gtk.ResponseType.OK):

Wyświetl plik

@ -96,16 +96,21 @@ BANDS_RANGES = [(None, None), (0.136, 0.137), (0.501, 0.504), (1.8, 2.0), (3.5,
ADIF_VERSION = "1.0"
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/ """
""" 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/ """
def __init__(self):
# 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). """
logging.debug("New ADIF instance created!")
def read(self, path):
""" Read an ADIF file with a specified path (given in the 'path' argument), and then parse it.
The output is a list of dictionaries (one dictionary per QSO), with each dictionary containing field-value pairs,
e.g. {FREQ:145.500, BAND:2M, MODE:FM}. """
""" Read an ADIF file and parse it.
:arg str path: The path to the ADIF file to read.
:returns: A list of dictionaries (one dictionary per QSO), with each dictionary containing field-value pairs, e.g. {FREQ:145.500, BAND:2M, MODE:FM}.
:rtype: list
:raises IOError: if the ADIF file does not exist or cannot be read (e.g. due to lack of read permissions).
"""
logging.debug("Reading in ADIF file with path: %s..." % path)
text = ""
@ -127,8 +132,11 @@ class ADIF:
def _parse_adi(self, text):
""" Parse some raw text (defined in the 'text' argument) for ADIF field data.
Outputs a list of dictionaries (one dictionary per QSO). Each dictionary contains the field-value pairs,
e.g. {FREQ:145.500, BAND:2M, MODE:FM}. """
:arg str text: The raw text from the ADIF file to parse.
:returns: A list of dictionaries (one dictionary per QSO). Each dictionary contains the field-value pairs, e.g. {FREQ:145.500, BAND:2M, MODE:FM}.
:rtype: list
"""
logging.debug("Parsing text from the ADIF file...")
@ -225,8 +233,13 @@ class ADIF:
return records
def write(self, records, path):
""" Write an ADIF file containing all the QSOs in the 'records' list. The desired path is specified in the 'path' argument.
This method returns None. """
""" Write an ADIF file containing all the QSOs in the 'records' list.
:arg list records: The list of QSO records to write.
:arg str path: The desired path of the ADIF file to write to.
:returns: None
:raises IOError: if the ADIF file cannot be written (e.g. due to lack of write permissions).
"""
logging.debug("Writing records to an ADIF file...")
try:
@ -266,8 +279,14 @@ class ADIF:
def is_valid(self, field_name, data, data_type):
""" Validate the data in a field (with name 'field_name') with respect to the ADIF specification.
This method returns either True or False to indicate whether the data is valid or not. """
""" Validate the data in a field with respect to the ADIF specification.
:arg str field_name: The name of the ADIF field.
:arg str data: The data of the ADIF field to validate.
:arg str data_type: The type of data to be validated. See http://www.adif.org/304/ADIF_304.htm#Data_Types for the full list with descriptions.
:returns: True or False to indicate whether the data is valid or not.
:rtype: bool
"""
logging.debug("Validating the following data in field '%s': %s" % (field_name, data))

Wyświetl plik

@ -21,20 +21,44 @@ from gi.repository import Gtk
import logging
def error(parent, message):
""" Display an error message. """
""" Display an error message.
:arg parent: The Gtk parent window/dialog.
:arg str message: The message to display to the user.
"""
logging.error(message)
_handle_gtk_dialog(parent, Gtk.MessageType.ERROR, message, "Error")
def info(parent, message):
""" Display some information. """
""" Display some information.
:arg parent: The Gtk parent window/dialog.
:arg str message: The message to display to the user.
"""
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. """
""" Ask the user a question. The dialog comes with 'Yes' and 'No' response buttons.
:arg parent: The Gtk parent window/dialog.
:arg str message: The message to display to the user.
:returns: The 'yes'/'no' response from the user.
:rtype: Gtk.ResponseType
"""
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.
:arg parent: The Gtk parent window/dialog.
:arg Gtk.MessageType msgtype: The type of message to present to the user (e.g. a question, or error message).
:arg str message: The message to display in the dialog.
:arg str title: The title to display at the top of the dialog.
:returns: The response from the user, based on which button they pushed.
:rtype: Gtk.ResponseType
"""
bt = Gtk.ButtonsType
buttons = bt.YES_NO if msgtype == Gtk.MessageType.QUESTION else bt.OK
dialog = Gtk.MessageDialog(parent, Gtk.DialogFlags.DESTROY_WITH_PARENT,

Wyświetl plik

@ -21,10 +21,14 @@ 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 """
""" A tool for tracking progress towards an award. Currently this only supports the DXCC award.
For more information visit http://www.arrl.org/dxcc """
def __init__(self, parent):
""" Set up a table for progress tracking purposes. """
""" Set up a table for progress tracking purposes.
:arg parent: The parent Gtk window.
"""
#TODO: This only considers the DXCC award for now.
logging.debug("New Awards instance created!")
@ -70,6 +74,7 @@ class Awards(Gtk.VBox):
def count(self):
""" Update the table for progress tracking. """
logging.debug("Counting the band/mode combinations for the awards table...")
# Wipe everything and start again
self.awards.clear()

Wyświetl plik

@ -25,16 +25,26 @@ from xml.dom import minidom
from auxiliary_dialogs import *
class CallsignLookupQRZ():
""" Uses qrz.com to lookup details about a particular callsign. """
""" Use qrz.com to lookup details about a particular callsign. """
def __init__(self, parent):
""" Initialise a new callsign lookup handler.
:arg parent: The parent Gtk dialog.
"""
self.parent = parent
self.connection = None
self.session_key = None
return
def connect(self, username, password):
""" Initiate a session with the qrz.com server. Hopefully this will return a session key. """
""" Initiate a session with the qrz.com server. Hopefully this will provide a session key.
:arg str username: The username of the qrz.com user account.
:arg str password: The password of the qrz.com user account.
:returns: True if a successful connection was made to the server, and False otherwise.
:rtype: bool
"""
logging.debug("Connecting to the qrz.com server...")
try:
self.connection = httplib.HTTPConnection('xmldata.qrz.com')
@ -64,8 +74,13 @@ class CallsignLookupQRZ():
return connected
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),
and return the data in the dictionary called fields_and_data. """
""" 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).
:arg bool ignore_prefix_suffix: True if callsign prefixes/suffixes should be removed prior to querying the server, False otherwise.
:returns: The data in a dictionary called fields_and_data.
:rtype: dict
"""
logging.debug("Looking up callsign. The full callsign (with a prefix and/or suffix) is %s" % full_callsign)
@ -138,7 +153,7 @@ class CallsignLookupQRZ():
class CallsignLookupHamQTH():
""" Uses hamqth.com to lookup details about a particular callsign. """
""" Use hamqth.com to lookup details about a particular callsign. """
def __init__(self, parent):
self.parent = parent
@ -147,7 +162,14 @@ class CallsignLookupHamQTH():
return
def connect(self, username, password):
""" Initiate a session with the hamqth.com server. Hopefully this will return a session key. """
""" Initiate a session with the hamqth.com server. Hopefully this will provide a session key.
:arg str username: The username of the hamqth.com user account.
:arg str password: The password of the hamqth.com user account.
:returns: True if a successful connection was made to the server, and False otherwise.
:rtype: bool
"""
logging.debug("Connecting to the hamqth.com server...")
try:
self.connection = httplib.HTTPConnection('www.hamqth.com')
@ -178,7 +200,12 @@ class CallsignLookupHamQTH():
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),
and return the data in the dictionary called fields_and_data. """
:arg str full_callsign: The callsign to look up (without any prefix/suffix stripping).
:arg bool ignore_prefix_suffix: True if callsign prefixes/suffixes should be removed prior to querying the server, False otherwise.
:returns: The data in a dictionary called fields_and_data.
:rtype: dict
"""
logging.debug("Looking up callsign. The full callsign (with a prefix and/or suffix) is %s" % full_callsign)
@ -244,7 +271,12 @@ class CallsignLookupHamQTH():
def strip(full_callsign):
""" Remove any prefixes or suffixes from a callsign. """
""" Remove any prefixes or suffixes from a callsign.
:arg str full_callsign: The callsign to be considered for prefix/suffix removal.
:returns: The callsign with prefixes/suffixes removed.
:rtype: str
"""
components = full_callsign.split("/") # We assume that prefixes or suffixes come before/after a forward slash character "/".
suffixes = ["P", "M", "A", "PM", "MM", "AM", "QRP"]

Wyświetl plik

@ -27,7 +27,10 @@ class DXCluster(Gtk.VBox):
""" A tool for connecting to a DX cluster (specifically Telnet-based DX clusters). """
def __init__(self, parent):
""" Set up the DX cluster's Gtk.VBox, and set up a timer so that PyQSO can retrieve new data from the Telnet server every few seconds. """
""" Set up the DX cluster's Gtk.VBox, and set up a timer so that PyQSO can retrieve new data from the Telnet server every few seconds.
:arg parent: The parent Gtk window.
"""
logging.debug("Setting up the DX cluster...")
Gtk.VBox.__init__(self, spacing=2)
@ -147,7 +150,11 @@ class DXCluster(Gtk.VBox):
return
def _on_telnet_io(self):
""" Retrieve any new data from the Telnet server and print it out in the Gtk.TextView widget. Always returns True to satisfy the GObject timer. """
""" Retrieve any new data from the Telnet server and print it out in the Gtk.TextView widget.
:returns: Always returns True to satisfy the GObject timer.
:rtype: bool
"""
if(self.connection):
text = self.connection.read_very_eager()
try:
@ -171,7 +178,10 @@ class DXCluster(Gtk.VBox):
return True
def set_connect_button_sensitive(self, sensitive):
""" Enable/disable the relevant buttons for connecting/disconnecting from a DX cluster, so that users cannot click the connect button if PyQSO is already connected. """
""" Enable/disable the relevant buttons for connecting/disconnecting from a DX cluster, so that users cannot click the connect button if PyQSO is already connected.
:arg bool sensitive: If True, enable the Connect button and disable the Disconnect button. If False, vice versa.
"""
self.buttons["CONNECT"].set_sensitive(sensitive)
self.buttons["DISCONNECT"].set_sensitive(not sensitive)
self.send.set_sensitive(not sensitive)

Wyświetl plik

@ -40,7 +40,10 @@ class GreyLine(Gtk.VBox):
""" A tool for visualising the grey line. """
def __init__(self, parent):
""" Set up the drawing canvas and the timer which will re-plot the grey line every 30 minutes. """
""" Set up the drawing canvas and the timer which will re-plot the grey line every 30 minutes.
:arg parent: The parent Gtk window.
"""
logging.debug("Setting up the grey line...")
Gtk.VBox.__init__(self, spacing=2)
self.parent = parent
@ -58,7 +61,11 @@ class GreyLine(Gtk.VBox):
return
def draw(self):
""" Draw the world map and the grey line on top of it. This method always returns True to satisfy the GObject timer. """
""" Draw the world map and the grey line on top of it.
:returns: Always returns True to satisfy the GObject timer, unless the necessary GreyLine dependencies are not satisfied (in which case, the method returns False so as to not re-draw the canvas).
:rtype: bool
"""
if(have_necessary_modules):
if(self.parent.toolbox.tools.get_current_page() != 1 or not self.parent.toolbox.get_visible()):

Wyświetl plik

@ -26,9 +26,14 @@ from adif import AVAILABLE_FIELD_NAMES_ORDERED
from record_dialog import *
class Log(Gtk.ListStore):
""" A Log object can store multiple Record objects. """
""" A single log inside of the whole logbook. A Log object can store multiple Record objects. """
def __init__(self, connection, name):
""" Set up a new Log object.
:arg connection: An sqlite database connection.
:arg str name: The name of the log (i.e. the sqlite table name).
"""
# The ListStore constructor needs to know the data types of the columns.
# The index is always an integer. We will assume the fields are strings.
@ -65,7 +70,10 @@ class Log(Gtk.ListStore):
def add_missing_db_columns(self):
""" Check whether each field name in AVAILABLE_FIELD_NAMES_ORDERED is in the database table. If not, add it
(with all entries being set to an empty string initially). """
(with all entries being set to an empty string initially).
:raises sqlite.Error, IndexError: if the existing database column names could not be obtained, or missing column names could not be added.
"""
logging.debug("Adding any missing database columns...")
# Get all the column names in the current database table.
@ -95,7 +103,10 @@ class Log(Gtk.ListStore):
return
def add_record(self, fields_and_data):
""" Add a record comprising data given in the 'fields_and_data' argument to the log. """
""" Add a record (or multiple records) to the log.
:arg fields_and_data: A list of dictionaries (or possibly just a single dictionary), with each dictionary representing a single QSO, to be added to the log.
"""
logging.debug("Adding record(s) to log...")
# If a dictionary is given, assume that we only have one record to add.
@ -159,7 +170,12 @@ class Log(Gtk.ListStore):
return
def delete_record(self, index, iter=None):
""" Delete a record with a specific index in the SQL database. The corresponding record is also deleted from the Gtk.ListStore data structure. Note that iter should always be given. It is given a default value of None for unit testing purposes only. """
""" Delete a specified record from the log. The corresponding record is also deleted from the Gtk.ListStore data structure.
:arg int index: The index of the record in the SQL database.
:arg iter: iter should always be given. It is given a default value of None for unit testing purposes only.
:raises sqlite.Error, IndexError: if the record could not be deleted.
"""
logging.debug("Deleting record from log...")
# Get the selected row in the logbook
try:
@ -176,7 +192,15 @@ class Log(Gtk.ListStore):
return
def edit_record(self, index, field_name, data, iter=None, column_index=None):
""" Edit a specified record by replacing the data in the field 'field_name' with the data given in the argument called 'data'. Note that both iter and column_index should always be given. These are given default values of None for unit testing purposes only. """
""" Edit a specified record by replacing the current data in a specified field with the data provided.
:arg int index: The index of the record in the SQL database.
:arg str field_name: The name of the field whose data should be modified.
:arg str data: The data that should replace the current data in the field.
:arg iter: Should always be given. A default value of None is used for unit testing purposes only.
:arg column_index: Should always be given. A default value of None is used for unit testing purposes only.
:raises sqlite.Error, IndexError: if the record could not be edited.
"""
logging.debug("Editing field '%s' in record %d..." % (field_name, index))
try:
with self.connection:
@ -193,7 +217,11 @@ class Log(Gtk.ListStore):
return
def remove_duplicates(self):
""" Remove any duplicate records from the log. Return the total number of duplicates, and the number of duplicates that were successfully removed. Hopefully these will be the same. """
""" Remove any duplicate records from the log.
:returns: The total number of duplicates, and the number of duplicates that were successfully removed. Hopefully these will be the same.
:rtype: tuple
"""
duplicates = self.get_duplicates()
if(len(duplicates) == 0):
return (0, 0) # Nothing to do here.
@ -213,7 +241,11 @@ class Log(Gtk.ListStore):
return (len(duplicates), removed)
def get_duplicates(self):
""" Find the duplicates in the log, based on the CALL, QSO_DATE, TIME_ON, FREQ and MODE fields, and return a list of their row IDs. """
""" Find the duplicates in the log, based on the CALL, QSO_DATE, TIME_ON, FREQ and MODE fields.
:returns: A list of row IDs corresponding to the duplicate records.
:rtype: list
"""
duplicates = []
try:
with self.connection:
@ -231,7 +263,12 @@ class Log(Gtk.ListStore):
return duplicates
def get_record_by_index(self, index):
""" Return a record with a given index in the log. The record is represented by a dictionary of field-value pairs. """
""" Return a record with a given index in the log.
:arg int index: The index of the record in the SQL database.
:returns: The desired record, represented by a dictionary of field-value pairs.
:rtype: dict
"""
try:
with self.connection:
c = self.connection.cursor()
@ -243,7 +280,11 @@ class Log(Gtk.ListStore):
return None
def get_all_records(self):
""" Return a list of all the records in the log. Each record is represented by a dictionary. """
""" Return a list of all the records in the log.
:returns: A list of all the records in the log. Each record is represented by a dictionary.
:rtype: dict
"""
try:
with self.connection:
c = self.connection.cursor()
@ -254,7 +295,11 @@ class Log(Gtk.ListStore):
return None
def get_number_of_records(self):
""" Return the total number of records in the log. """
""" Return the total number of records in the log.
:returns: The total number of records in the log.
:rtype: int
"""
try:
with self.connection:
c = self.connection.cursor()

Wyświetl plik

@ -21,9 +21,16 @@ 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):
""" Create and show the log name dialog to the user.
:arg parent: The parent Gtk window.
:arg title: The title of the dialog. If this is None, it is assumed that a new log is going to be created.
:arg name: The existing name of the Log object. Defaults to None if not specified (because the Log does not yet exist).
"""
if(title is None):
title = "New Log"
else:
@ -47,6 +54,12 @@ class LogNameDialog(Gtk.Dialog):
return
def get_log_name(self):
""" Return the log name specified in the Gtk.Entry box by the user.
:returns: The log's name.
:rtype: str
"""
logging.debug("Retrieving the log name from the LogNameDialog...")
return self.entry.get_text()

Wyświetl plik

@ -33,7 +33,11 @@ class Logbook(Gtk.Notebook):
""" A Logbook object can store multiple Log objects. """
def __init__(self, parent):
""" Create a new Logbook object and initialise the list of Logs.
:arg parent: The parent Gtk window.
"""
Gtk.Notebook.__init__(self)
self.parent = parent
@ -69,11 +73,13 @@ class Logbook(Gtk.Notebook):
open(path, 'w').close()
# Open the new logbook, ready for use.
self.open(path=path)
return
def open(self, widget=None, path=None):
""" Open a logbook, and render all the logs within it.
An optional 'path' argument can be specified if the database file location is known.
Otherwise, a file selection dialog will appear. """
""" Open a logbook, and render all the logs within it.
:arg str path: An optional argument containing the database file location, if already known. If this is None, a file selection dialog will appear.
"""
if(path is None):
# If no path has been provided, get one from a "File Open" dialog.
@ -92,7 +98,7 @@ class Logbook(Gtk.Notebook):
logging.debug("No file path specified.")
return
connected = self.db_connect(path=path)
connected = self.db_connect(path)
if(connected):
# If the connection setup was successful, then open all the logs in the database
@ -169,8 +175,11 @@ class Logbook(Gtk.Notebook):
logging.debug("Unable to disconnect from the database. No logs were closed.")
return
def db_connect(self, path=None):
""" Create an SQL database connection to the Logbook's data source """
def db_connect(self, path):
""" Create an SQL database connection to the Logbook's data source.
:arg str path: The path of the database file.
"""
logging.debug("Attempting to connect to the logbook database...")
# Try setting up the SQL database connection
@ -188,7 +197,12 @@ class Logbook(Gtk.Notebook):
return True
def db_disconnect(self):
""" Destroy the connection to the Logbook's data source. """
""" Destroy the connection to the Logbook's data source.
:returns: True if the connection was successfully destroyed, and False otherwise.
:rtype: bool
"""
logging.debug("Cleaning up any existing database connections...")
if(self.connection):
try:
@ -202,6 +216,7 @@ class Logbook(Gtk.Notebook):
def _create_dummy_page(self):
""" Create a blank page in the Gtk.Notebook for the "+" (New Log) tab. """
blank_treeview = Gtk.TreeView()
# Allow the Log to be scrolled up/down
sw = Gtk.ScrolledWindow()
@ -231,6 +246,7 @@ class Logbook(Gtk.Notebook):
def _create_summary_page(self):
""" Create a summary page containing the number of logs in the logbook, and the logbook's modification date. """
vbox = Gtk.VBox()
# Database name in large font at the top of the summary page
@ -275,6 +291,7 @@ class Logbook(Gtk.Notebook):
def update_summary(self):
""" Update the information presented on the summary page. """
self.summary["LOG_COUNT"].set_label(str(self.get_number_of_logs()))
self.summary["QSO_COUNT"].set_label(str(self.get_number_of_qsos()))
try:
@ -285,6 +302,8 @@ class Logbook(Gtk.Notebook):
return
def _on_switch_page(self, widget, label, new_page):
""" Handle a tab/page change, and enable/disable the relevant Record-related buttons. """
if(new_page == self.get_n_pages()-1): # The last (right-most) tab is the "New Log" tab.
self.stop_emission("switch-page")
@ -299,6 +318,7 @@ class Logbook(Gtk.Notebook):
def new_log(self, widget=None):
""" Create a new log in the logbook. """
if(self.connection is None):
return
exists = True
@ -339,7 +359,10 @@ class Logbook(Gtk.Notebook):
return
def delete_log(self, widget, page=None):
""" Delete the log that is currently selected in the logbook. """
""" Delete the log that is currently selected in the logbook.
:arg Gtk.Widget page: An optional argument corresponding to the currently-selected page/tab.
"""
if(self.connection is None):
return
@ -386,14 +409,21 @@ class Logbook(Gtk.Notebook):
self.parent.toolbox.awards.count()
return
def filter_logs(self, widget):
def filter_logs(self, widget=None):
""" Re-filter all the logs when the user-defined expression is changed. """
for i in range(0, len(self.filter)):
self.filter[i].refilter()
return
def _filter_by_callsign(self, model, iter, data):
""" Filter all the logs in the logbook by the callsign field, based on a user-defined expression. """
""" Filter all the logs in the logbook by the callsign field, based on a user-defined expression.
:arg Gtk.TreeModel model: The model used to filter the log data.
:arg Gtk.TreeIter iter: A pointer to a particular row in the model.
:arg data: The user-defined expression to filter by.
:returns: True if a record matches the expression, or if there is nothing to filter. Otherwise, returns False.
:rtype: bool
"""
value = model.get_value(iter, 1)
callsign = self.parent.toolbar.filter_source.get_text()
@ -406,7 +436,10 @@ class Logbook(Gtk.Notebook):
return callsign.upper() in value or callsign.lower() in value
def _render_log(self, index):
""" Render the Log (identified by 'index') in the Gtk.Notebook. """
""" Render a Log in the Gtk.Notebook.
:arg int index: The index of the Log (in the list of Logs) to render.
"""
self.filter.append(self.logs[index].filter_new(root=None))
# Set the callsign column as the column we want to filter by
self.filter[index].set_visible_func(self._filter_by_callsign, data=None)
@ -476,7 +509,15 @@ class Logbook(Gtk.Notebook):
return
def _compare_date_and_time(self, model, row1, row2, user_data):
""" Compares two rows in a Gtk.ListStore, and sorts by both date and time. """
""" Compare two rows (let's call them A and B) in a Gtk.ListStore, and sort by both date and time.
:arg Gtk.TreeModel model: The model used to sort the log data.
:arg Gtk.TreeIter row1: The pointer to row A.
:arg Gtk.TreeIter row2: The pointer to row B.
:arg user_data: The specific column from which to retrieve data for rows A and B.
:returns: 1 if Row B's date/time is more recent than Row A's; 0 if both dates and times are the same; -1 if Row A's date/time is more recent than Row B's.
:rtype: int
"""
date1 = model.get_value(row1, user_data[0])
date2 = model.get_value(row2, user_data[0])
time1 = model.get_value(row1, user_data[1])
@ -495,7 +536,15 @@ class Logbook(Gtk.Notebook):
return -1
def _compare_default(self, model, row1, row2, user_data):
""" The default sorting function for all Gtk.ListStore objects. """
""" The default sorting function for all Gtk.ListStore objects.
:arg Gtk.TreeModel model: The model used to sort the log data.
:arg Gtk.TreeIter row1: The pointer to row A.
:arg Gtk.TreeIter row2: The pointer to row B.
:arg user_data: The specific column from which to retrieve data for rows A and B.
:returns: 1 if the value of Row A's column value is less than Row B's column value; 0 if both values are the same; -1 if Row A's column value is greater than Row B's column value.
:rtype: int
"""
value1 = model.get_value(row1, user_data)
value2 = model.get_value(row2, user_data)
if(value1 < value2):
@ -506,7 +555,11 @@ class Logbook(Gtk.Notebook):
return -1
def sort_log(self, widget, column_index):
""" Sort the log (that is currently selected) based on the column identified by column_index. """
""" Sort the log (that is currently selected) with respect to a given field.
:arg int column_index: The index of the column to sort by.
"""
log_index = self._get_log_index()
column = self.treeview[log_index].get_column(column_index)
@ -757,6 +810,11 @@ class Logbook(Gtk.Notebook):
return
def _begin_print(self, operation, context):
""" Specify the layout/position/font of the text on the pages to be printed.
:arg Gtk.PrintOperation operation: The printing API.
:arg Gtk.PrintContext context: Used to draw/render the pages to print.
"""
width = context.get_width()
height = context.get_height()
layout = context.create_pango_layout()
@ -780,6 +838,12 @@ class Logbook(Gtk.Notebook):
return
def _draw_page(self, operation, context, page_number):
""" Render the QSO details on the page.
:arg Gtk.PrintOperation operation: The printing API.
:arg Gtk.PrintContext context: Used to draw/render the pages to print.
:arg int page_number: The current page number.
"""
cr = context.get_cairo_context()
cr.set_source_rgb(0, 0, 0)
layout = context.create_pango_layout()
@ -798,6 +862,7 @@ class Logbook(Gtk.Notebook):
return
def add_record_callback(self, widget):
""" A callback function used to add a particular record/QSO. """
# Get the log index
try:
log_index = self._get_log_index()
@ -844,6 +909,8 @@ class Logbook(Gtk.Notebook):
return
def delete_record_callback(self, widget):
""" A callback function used to delete a particular record/QSO. """
# Get the log index
try:
log_index = self._get_log_index()
@ -875,8 +942,10 @@ class Logbook(Gtk.Notebook):
return
def edit_record_callback(self, widget, path, view_column):
# Note: the path and view_column arguments need to be passed in
# since they associated with the row-activated signal.
""" A callback function used to edit a particular record/QSO.
Note that the widget, path and view_column arguments are not used,
but need to be passed in since they associated with the row-activated signal
which is generated when the user double-clicks on a record. """
# Get the log index
try:
@ -954,18 +1023,31 @@ class Logbook(Gtk.Notebook):
return
def get_number_of_logs(self):
""" Return the total number of logs in the logbook. """
""" Return the total number of logs in the logbook.
:returns: The total number of logs in the logbook.
:rtype: int
"""
return len(self.logs)
def get_number_of_qsos(self):
""" Return the total number of QSOs/records in the whole logbook. """
""" Return the total number of QSOs/records in the whole logbook.
:returns: The total number of QSOs/records in the whole logbook.
:rtype: int
"""
total = 0
for log in self.logs:
total += log.get_number_of_records()
return total
def log_name_exists(self, table_name):
""" Return True if the log name already exists in the logbook, and False if it does not already exist. Return None if there is a database error. """
""" Determine whether a Log object with a given name exists in the SQL database.
:arg str table_name: The name of the log (i.e. the name of the table in the SQL database).
:returns: True if the log name already exists in the logbook; False if it does not already exist; None if there is a database error.
:rtype: bool or None
"""
try:
with self.connection:
c = self.connection.cursor()
@ -980,7 +1062,12 @@ class Logbook(Gtk.Notebook):
return None
def _get_log_index(self, name=None):
""" Given the name of a log, return its index in the self.log list. """
""" Given the name of a log, return its index in the list of Log objects.
:arg str name: The name of the log. If None, use the name of the currently-selected log.
:returns: The index of the named log in the list of Log objects.
:rtype: int
"""
if(name is None):
# If no page name is supplied, then just use the currently selected page
page_index = self.get_current_page() # Gets the index of the selected tab in the logbook

Wyświetl plik

@ -2,7 +2,7 @@
# Copyright (C) 2012 Christian T. Jacobs.
# This logbook is part of PyQSO.
# 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
@ -23,8 +23,14 @@ import ConfigParser
import os.path
class Menu(Gtk.MenuBar):
""" The PyQSO menu bar along the top of the main window. """
def __init__(self, parent):
""" Set up all menu items and connect to the various functions.
:arg parent: The parent Gtk window.
"""
logging.debug("New Menu instance created!")
# First let's call the constructor of the super class (Gtk.MenuBar)
@ -246,6 +252,10 @@ class Menu(Gtk.MenuBar):
return
def set_logbook_item_sensitive(self, sensitive):
""" Enable/disable logbook-related menu items.
:arg bool sensitive: If True, enable the 'new logbook' and 'open logbook' menu items. If False, disable them.
"""
logging.debug("Setting the 'Create/Open Logbook' menu item's sensitivity to: %s..." % sensitive)
self.items["NEW_LOGBOOK"].set_sensitive(sensitive)
self.items["OPEN_LOGBOOK"].set_sensitive(sensitive)
@ -254,6 +264,10 @@ class Menu(Gtk.MenuBar):
return
def set_log_items_sensitive(self, sensitive):
""" Enable/disable log-related menu items.
:arg bool sensitive: If True, enable all the log-related menu items. If False, disable them all.
"""
logging.debug("Setting log-related menu item sensitivity to: %s..." % sensitive)
for item_name in ["NEW_LOG", "DELETE_LOG", "RENAME_LOG", "IMPORT_LOG", "EXPORT_LOG", "PRINT_LOG"]:
self.items[item_name].set_sensitive(sensitive)
@ -261,6 +275,10 @@ class Menu(Gtk.MenuBar):
return
def set_record_items_sensitive(self, sensitive):
""" Enable/disable record-related menu items.
:arg bool sensitive: If True, enable all the record-related menu items. If False, disable them all.
"""
logging.debug("Setting record-related menu item sensitivity to: %s..." % sensitive)
for item_name in ["ADD_RECORD", "EDIT_RECORD", "DELETE_RECORD", "REMOVE_DUPLICATES"]:
self.items[item_name].set_sensitive(sensitive)

Wyświetl plik

@ -32,8 +32,11 @@ except ImportError:
from pyqso.adif import AVAILABLE_FIELD_NAMES_FRIENDLY, AVAILABLE_FIELD_NAMES_ORDERED, MODES
class PreferencesDialog(Gtk.Dialog):
""" A dialog to specify the PyQSO preferences. """
def __init__(self, parent):
""" Set up the various pages of the preferences dialog. """
logging.debug("Setting up the preferences dialog...")
Gtk.Dialog.__init__(self, title="Preferences", parent=parent, flags=Gtk.DialogFlags.DESTROY_WITH_PARENT, buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK))
@ -64,6 +67,7 @@ class PreferencesDialog(Gtk.Dialog):
def commit(self):
""" 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()
@ -104,7 +108,8 @@ class PreferencesDialog(Gtk.Dialog):
return
class GeneralPage(Gtk.VBox):
""" The section of the preferences dialog containing general preferences. """
def __init__(self):
logging.debug("Setting up the General page of the preferences dialog...")
@ -140,7 +145,8 @@ class GeneralPage(Gtk.VBox):
return data
class ViewPage(Gtk.VBox):
""" The section of the preferences dialog containing view-related preferences. """
def __init__(self):
logging.debug("Setting up the View page of the preferences dialog...")
@ -191,7 +197,8 @@ class ViewPage(Gtk.VBox):
return data
class HamlibPage(Gtk.VBox):
""" The section of the preferences dialog containing Hamlib-related preferences. """
def __init__(self):
logging.debug("Setting up the Hamlib page of the preferences dialog...")
@ -272,7 +279,8 @@ class HamlibPage(Gtk.VBox):
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...")
@ -442,6 +450,7 @@ class RecordsPage(Gtk.VBox):
return data
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...")

Wyświetl plik

@ -36,11 +36,14 @@ from 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):
""" Set up the layout of the record dialog.
If a record index is specified in the 'index' argument, then the dialog turns into 'edit record mode' and fills the data sources with the existing data in the log.
If the 'index' argument is None, then the dialog starts off with nothing in the data sources (e.g. the Gtk.Entry boxes). """
""" Set up the layout of the record dialog, populate the various fields with the QSO details (if the record already exists), and show the dialog to the user.
:arg parent: The parent Gtk window.
:arg log: The log to which the record belongs (or will belong).
:arg int index: If specified, then the dialog turns into 'edit record mode' and fills the data sources (e.g. the Gtk.Entry boxes) with the existing data in the log. If not specified (i.e. index is None), then the dialog starts off with nothing in the data sources.
"""
logging.debug("Setting up the record dialog...")
@ -425,7 +428,12 @@ class RecordDialog(Gtk.Dialog):
return
def get_data(self, field_name):
""" Return the data for a specified field (with name 'field_name') from the Gtk.Entry/Gtk.ComboBoxText/etc boxes in the record dialog. """
""" Return the data for a specified field from the Gtk.Entry/Gtk.ComboBoxText/etc boxes in the record dialog.
:arg str field_name: The name of the field containing the desired data.
:returns: The data in the specified field.
:rtype: str
"""
logging.debug("Retrieving the data in field %s from the record dialog..." % field_name)
if(field_name == "CALL"):
# Always show the callsigns in upper case.
@ -562,6 +570,10 @@ 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):
""" Set up the calendar widget and show it to the user.
:arg parent: The parent Gtk window/dialog.
"""
logging.debug("Setting up a calendar dialog...")
Gtk.Dialog.__init__(self, title="Select Date", parent=parent, flags=Gtk.DialogFlags.DESTROY_WITH_PARENT, buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.calendar = Gtk.Calendar()
@ -571,7 +583,11 @@ class CalendarDialog(Gtk.Dialog):
return
def get_date(self):
""" Return the date from the Gtk.Calendar widget in YYYYMMDD format. """
""" Return the date from the Gtk.Calendar widget in YYYYMMDD format.
:returns: The date from the calendar in YYYYMMDD format.
:rtype: str
"""
logging.debug("Retrieving the date from the calendar widget...")
(year, month, day) = self.calendar.get_date()
# If necessary, add on leading zeros so the YYYYMMDD format is followed.

Wyświetl plik

@ -25,6 +25,11 @@ class TelnetConnectionDialog(Gtk.Dialog):
This can be used to connect to DX clusters. """
def __init__(self, parent):
""" Set up and show the Telnet connection dialog to the user.
:arg parent: The parent Gtk window/dialog.
"""
logging.debug("Setting up the Telnet connection dialog...")
Gtk.Dialog.__init__(self, title="New Telnet Connection", parent=parent, flags=Gtk.DialogFlags.DESTROY_WITH_PARENT, buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK))
@ -74,7 +79,11 @@ class TelnetConnectionDialog(Gtk.Dialog):
return
def get_connection_info(self):
""" Return the host and login information stored in the Gtk.Entry boxes. """
""" Return the host and login information stored in the Gtk.Entry boxes.
:returns: A dictionary of Telnet connection-related information (username, password, port, host).
:rtype: dict
"""
logging.debug("Returning Telnet connection information...")
return self.sources

Wyświetl plik

@ -21,8 +21,11 @@ from gi.repository import Gtk
import logging
class Toolbar(Gtk.HBox):
""" The toolbar underneath the menu bar. """
def __init__(self, parent):
""" Set up the various buttons in the toolbar, and connect to their corresponding functions. """
logging.debug("Setting up the toolbar...")
Gtk.HBox.__init__(self, spacing=2)
@ -111,18 +114,26 @@ class Toolbar(Gtk.HBox):
return
def set_logbook_button_sensitive(self, sensitive):
logging.debug("Setting the 'Create/Open Logbook' toolbar item's sensitivity to: %s..." % sensitive)
""" Enable/disable logbook-related toolbar items.
:arg bool sensitive: If True, enable the 'new logbook' and 'open logbook' toolbar items. If False, disable them.
"""
logging.debug("Setting logbook-related toolbar item sensitivity to: %s..." % sensitive)
self.buttons["NEW_LOGBOOK"].set_sensitive(sensitive)
self.buttons["OPEN_LOGBOOK"].set_sensitive(sensitive)
self.buttons["CLOSE_LOGBOOK"].set_sensitive(not sensitive)
logging.debug("Set the 'Create/Open Logbook' toolbar item's sensitivity to: %s." % sensitive)
logging.debug("Set logbook-related toolbar item sensitivity to: %s." % sensitive)
return
def set_record_buttons_sensitive(self, sensitive):
logging.debug("Setting record-related menu item sensitivity to: %s..." % sensitive)
""" Enable/disable record-related toolbar items.
:arg bool sensitive: If True, enable all the record-related toolbar items. If False, disable them all.
"""
logging.debug("Setting record-related toolbar item sensitivity to: %s..." % sensitive)
for button_name in ["ADD_RECORD", "EDIT_RECORD", "DELETE_RECORD"]:
self.buttons[button_name].set_sensitive(sensitive)
logging.debug("Set record-related menu item sensitivity to: %s." % sensitive)
logging.debug("Set record-related toolbar item sensitivity to: %s." % sensitive)
return

Wyświetl plik

@ -28,6 +28,8 @@ class Toolbox(Gtk.Frame):
""" Contains a Gtk.Notebook full of amateur radio-related tools. """
def __init__(self, parent):
""" Instantiate and insert the various tools into the toolbox. """
logging.debug("Setting up the toolbox...")
Gtk.Frame.__init__(self)