kopia lustrzana https://github.com/ctjacobs/pyqso
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
rodzic
76b673475e
commit
6407c4a9cc
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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. """
|
||||
|
|
|
@ -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
|
||||
|
|
172
res/pyqso.glade
172
res/pyqso.glade
|
@ -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 <http://www.gnu.org/licenses/>.</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>
|
||||
|
|
Ładowanie…
Reference in New Issue