More work on the Cabrillo exporting functionality.

Added a dialog that allows the user to specify the callsign used during a contest, and the contest's name.
pull/61/head
Christian T. Jacobs 2017-04-05 22:42:43 +01:00
rodzic 76b673475e
commit 6407c4a9cc
5 zmienionych plików z 296 dodań i 19 usunięć

Wyświetl plik

@ -369,6 +369,7 @@ class ADIF:
logging.error("An error occurred when writing the ADIF file.")
logging.exception(e)
logging.info("Log exported to %s in ADIF format." % (path))
return
def is_valid(self, field_name, data, data_type):

Wyświetl plik

@ -17,10 +17,13 @@
# 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
import logging
CABRILLO_VERSION = "3.0"
CONTESTS = ["", "AP-SPRINT", "ARRL-10", "ARRL-160", "ARRL-222", "ARRL-DX-CW", "ARRL-DX-SSB", "ARRL-RR-PH", "ARRL-RR-DIG", "ARRL-RR-CW", "ARRL-SCR", "ARRL-SS-CW", "ARRL-SS-SSB", "ARRL-UHF-AUG", "ARRL-VHF-JAN", "ARRL-VHF-JUN", "ARRL-VHF-SEP", "ARRL-RTTY", "BARTG-RTTY", "CQ-160-CW", "CQ-160-SSB", "CQ-WPX-CW", "CQ-WPX-RTTY", "CQ-WPX-SSB", "CQ-VHF", "CQ-WW-CW", "CQ-WW-RTTY", "CQ-WW-SSB", "DARC-WAEDC-CW", "DARC-WAEDC-RTTY", "DARC-WAEDC-SSB", "DL-DX-RTTY", "DRCG-WW-RTTY", "FCG-FQP", "IARU-HF", "JIDX-CW", "JIDX-SSB", "NAQP-CW", "NAQP-SSB", "NA-SPRINT-CW", "NA-SPRINT-SSB", "NCCC-CQP", "NEQP", "OCEANIA-DX-CW", "OCEANIA-DX-SSB", "RDXC", "RSGB-IOTA", "SAC-CW", "SAC-SSB", "STEW-PERRY", "TARA-RTTY"]
class Cabrillo:
@ -31,7 +34,7 @@ class Cabrillo:
""" Initialise class for I/O of files using the Cabrillo format. """
return
def write(self, records, path):
def write(self, records, path, contest="", mycall=""):
logging.debug("Writing records to an Cabrillo file...")
try:
@ -40,12 +43,17 @@ class Cabrillo:
# Header
f.write("""START-OF-LOG: %s\n""" % (CABRILLO_VERSION))
f.write("""CREATED-BY: PyQSO v1.0.0\n""")
f.write("""CALLSIGN: %s\n""" % (mycall))
f.write("""CONTEST: %s\n""" % (contest))
# Write each record to the file.
for r in records:
# Frequency
freq = r["FREQ"]
# Frequency. Note that this must be in kHz. The frequency is stored in MHz in the database, so it's converted to kHz here.
try:
freq = str(float(r["FREQ"])*1e3)
except ValueError as e:
freq = ""
# Mode
if(r["MODE"] == "SSB"):
@ -65,7 +73,7 @@ class Cabrillo:
time = r["TIME_ON"]
# The callsign that was used when operating the contest station.
call_sent = "TEST"
call_sent = mycall
# Exchange (the part sent to the distant station)
exch_sent = r["RST_SENT"]
@ -93,4 +101,52 @@ class Cabrillo:
logging.error("An error occurred when writing the Cabrillo file.")
logging.exception(e)
logging.info("Log exported to %s in Cabrillo format." % (path))
return
class CabrilloExportDialog:
""" A handler for the Gtk.Dialog through which a user can specify Cabrillo log details. """
def __init__(self, application):
""" Create and show the Cabrillo export dialog to the user.
:arg application: The PyQSO application containing the main Gtk window, etc.
"""
logging.debug("Building new Cabrillo export dialog...")
self.builder = application.builder
glade_file_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), os.pardir, "res/pyqso.glade")
self.builder.add_objects_from_file(glade_file_path, ("cabrillo_export_dialog",))
self.dialog = self.builder.get_object("cabrillo_export_dialog")
self.contest_combo = self.builder.get_object("cabrillo_export_contest_combo")
self.mycall_entry = self.builder.get_object("cabrillo_export_mycall_entry")
for contest in CONTESTS:
self.contest_combo.append_text(contest)
self.dialog.show_all()
logging.debug("Cabrillo export dialog built.")
return
@property
def contest(self):
""" Return the name of the contest.
:returns: The name of the contest.
:rtype: str
"""
return self.contest_combo.get_active_text()
@property
def mycall(self):
""" Return the callsign used during the contest.
:returns: The callsign used during the contest.
:rtype: str
"""
return self.mycall_entry.get_text()

Wyświetl plik

@ -45,6 +45,7 @@ except ImportError as e:
have_matplotlib = False
from pyqso.adif import *
from pyqso.cabrillo import *
from pyqso.log import *
from pyqso.auxiliary_dialogs import *
from pyqso.log_name_dialog import LogNameDialog
@ -541,7 +542,7 @@ class Logbook:
log = self.logs[log_index]
# We also need the page's index in order to remove it using remove_page below.
# This may not be the same as what self.get_current_page() returns.
# This may not be the same as what get_current_page() returns.
page_index = self.notebook.page_num(page)
if(page_index == 0 or page_index == self.notebook.get_n_pages()-1): # Only the "New Log" tab is present (i.e. no actual logs in the logbook)
@ -900,9 +901,9 @@ class Logbook:
return
def export_log(self, widget=None):
def export_log_adif(self, widget=None):
""" Export the log (that is currently selected) to an ADIF file. """
page_index = self.get_current_page() # Gets the index of the selected tab in the logbook
page_index = self.notebook.get_current_page() # Gets the index of the selected tab in the logbook
if(page_index == 0): # If we are on the Summary page...
logging.debug("No log currently selected!")
return
@ -910,7 +911,7 @@ class Logbook:
log_index = self._get_log_index()
log = self.logs[log_index]
dialog = Gtk.FileChooserDialog("Export Log to File",
dialog = Gtk.FileChooserDialog("Export Log as ADIF",
self.application.window,
Gtk.FileChooserAction.SAVE,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
@ -946,6 +947,63 @@ class Logbook:
error(self.application.window, "Could not retrieve the records from the SQL database. No records have been exported.")
return
def export_log_cabrillo(self, widget=None):
""" Export the log (that is currently selected) to a Cabrillo file. """
page_index = self.notebook.get_current_page() # Gets the index of the selected tab in the logbook
if(page_index == 0): # If we are on the Summary page...
logging.debug("No log currently selected!")
return
log_index = self._get_log_index()
log = self.logs[log_index]
dialog = Gtk.FileChooserDialog("Export Log as Cabrillo",
self.application.window,
Gtk.FileChooserAction.SAVE,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
dialog.set_do_overwrite_confirmation(True)
filter = Gtk.FileFilter()
filter.set_name("All Cabrillo files (*.log, *.LOG)")
filter.add_pattern("*.log")
filter.add_pattern("*.LOG")
dialog.add_filter(filter)
filter = Gtk.FileFilter()
filter.set_name("All files")
filter.add_pattern("*")
dialog.add_filter(filter)
response = dialog.run()
if(response == Gtk.ResponseType.OK):
path = dialog.get_filename()
else:
path = None
dialog.destroy()
if(path is None):
logging.debug("No file path specified.")
else:
# Get Cabrillo-specific fields, such as the callsign used during a contest and the contest's name.
ced = CabrilloExportDialog(self.application)
response = ced.dialog.run()
if(response == Gtk.ResponseType.OK):
contest = ced.contest
mycall = ced.mycall
else:
ced.dialog.destroy()
return
ced.dialog.destroy()
cabrillo = Cabrillo()
records = log.get_all_records()
if(records is not None):
cabrillo.write(records, path, contest=contest, mycall=mycall)
else:
error(self.application.window, "Could not retrieve the records from the SQL database. No records have been exported.")
return
def print_log(self, widget=None):
""" Print all the records in the log (that is currently selected).
Note that only a few important fields are printed because of the restricted width of the page. """

Wyświetl plik

@ -72,9 +72,13 @@ class Menu:
self.items["IMPORT_LOG"] = self.builder.get_object("mitem_import_log")
self.items["IMPORT_LOG"].connect("activate", self.application.logbook.import_log)
# Export the current log
self.items["EXPORT_LOG"] = self.builder.get_object("mitem_export_log")
self.items["EXPORT_LOG"].connect("activate", self.application.logbook.export_log)
# Export the current log as ADIF
self.items["EXPORT_LOG_ADIF"] = self.builder.get_object("mitem_export_log_adif")
self.items["EXPORT_LOG_ADIF"].connect("activate", self.application.logbook.export_log_adif)
# Export the current log as Cabrillo
self.items["EXPORT_LOG_CABRILLO"] = self.builder.get_object("mitem_export_log_cabrillo")
self.items["EXPORT_LOG_CABRILLO"].connect("activate", self.application.logbook.export_log_cabrillo)
# Print log
self.items["PRINT_LOG"] = self.builder.get_object("mitem_print_log")
@ -145,7 +149,7 @@ class Menu:
: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"]:
for item_name in ["NEW_LOG", "DELETE_LOG", "RENAME_LOG", "IMPORT_LOG", "EXPORT_LOG_ADIF", "EXPORT_LOG_CABRILLO", "PRINT_LOG"]:
self.items[item_name].set_sensitive(sensitive)
logging.debug("Set log-related menu item sensitivity to: %s." % sensitive)
return

Wyświetl plik

@ -2,6 +2,148 @@
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkDialog" id="cabrillo_export_dialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Cabrillo Export</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="transient_for">pyqso</property>
<child internal-child="vbox">
<object class="GtkBox" id="cabrillo_export_dialog_vbox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="cabrillo_export_dialog_action_area">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cabrillo_export_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="cabrillo_export_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">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="cabrillo_export_contest_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="cabrillo_export_contest_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Contest</property>
<property name="width_chars">15</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="GtkComboBoxText" id="cabrillo_export_contest_combo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="has_entry">True</property>
<child internal-child="entry">
<object class="GtkEntry" id="cabrillo_export_contest_combo_entry">
<property name="can_focus">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="cabrillo_export_mycall_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="cabrillo_export_mycall_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">My callsign</property>
<property name="width_chars">15</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="cabrillo_export_mycall_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="padding">2</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">cabrillo_export_cancel_button</action-widget>
<action-widget response="-5">cabrillo_export_ok_button</action-widget>
</action-widgets>
</object>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
@ -68,6 +210,11 @@
<property name="stock">gtk-open</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="image29">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-go-back</property>
</object>
<object class="GtkImage" id="image3">
<property name="visible">True</property>
<property name="can_focus">False</property>
@ -213,14 +360,23 @@
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="mitem_export_log">
<property name="label" translatable="yes">Export Log</property>
<object class="GtkImageMenuItem" id="mitem_export_log_adif">
<property name="label" translatable="yes">Export Log as ADIF</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image10</property>
<property name="use_stock">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="mitem_export_log_cabrillo">
<property name="label" translatable="yes">Export Log as Cabrillo</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image29</property>
<property name="use_stock">False</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem3">
<property name="visible">True</property>
@ -963,11 +1119,13 @@ along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.</pro
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Log Name</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">6</property>
<property name="padding">2</property>
<property name="position">0</property>
</packing>
</child>
@ -2339,7 +2497,7 @@ Base64-encoded plain text in the configuration file.</property>
</packing>
</child>
<child>
<object class="GtkBox" id="preferences_adif_vbox">
<object class="GtkBox" id="preferences_import_export_vbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
@ -2382,7 +2540,7 @@ Base64-encoded plain text in the configuration file.</property>
<object class="GtkLabel" id="preferences_adif_import_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Import</property>
<property name="label" translatable="yes">ADIF Import</property>
</object>
</child>
</object>
@ -2398,10 +2556,10 @@ Base64-encoded plain text in the configuration file.</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel" id="preferences_adif_label">
<object class="GtkLabel" id="preferences_import_export_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">ADIF</property>
<property name="label" translatable="yes">Import/Export</property>
</object>
<packing>
<property name="position">3</property>