2015-10-12 00:23:37 +00:00
#!/usr/bin/env python3
2013-03-23 14:36:25 +00:00
2017-03-20 13:06:01 +00:00
# Copyright (C) 2013-2017 Christian Thomas Jacobs.
2013-03-23 14:36:25 +00:00
# This file is part of PyQSO.
# PyQSO is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PyQSO is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PyQSO. If not, see <http://www.gnu.org/licenses/>.
2017-03-02 10:45:49 +00:00
from gi . repository import Gtk , Gdk
2013-03-23 14:36:25 +00:00
import logging
2017-03-01 10:16:03 +00:00
import os
2017-02-07 14:17:14 +00:00
try :
import configparser
except ImportError :
import ConfigParser as configparser
2013-07-13 15:43:27 +00:00
from datetime import datetime
2013-07-13 19:23:53 +00:00
from os . path import expanduser
2013-07-17 15:40:21 +00:00
import base64
2013-07-27 18:22:54 +00:00
try :
2016-01-27 16:23:09 +00:00
import Hamlib
have_hamlib = True
2013-09-14 20:10:52 +00:00
except ImportError :
2016-01-27 16:23:09 +00:00
logging . warning ( " Could not import the Hamlib module! " )
have_hamlib = False
2013-03-23 14:36:25 +00:00
2015-11-17 01:03:50 +00:00
from pyqso . adif import *
2015-10-12 00:23:37 +00:00
from pyqso . callsign_lookup import *
from pyqso . auxiliary_dialogs import *
2017-02-24 00:20:43 +00:00
from pyqso . calendar_dialog import CalendarDialog
2016-01-27 16:23:09 +00:00
2017-02-24 00:05:42 +00:00
2017-03-01 10:16:03 +00:00
class RecordDialog :
2016-01-27 16:23:09 +00:00
""" A dialog through which users can enter information about a QSO/record. """
2017-03-31 09:06:11 +00:00
def __init__ ( self , application , log , index = None ) :
2016-01-27 16:23:09 +00:00
""" 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.
2017-03-31 09:06:11 +00:00
: arg application : The PyQSO application containing the main Gtk window , etc .
2016-01-27 16:23:09 +00:00
: 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... " )
2017-03-31 09:06:11 +00:00
self . application = application
self . builder = self . application . builder
2017-07-05 23:36:17 +00:00
glade_file_path = os . path . join ( os . path . realpath ( os . path . dirname ( __file__ ) ) , " res " , " pyqso.glade " )
2017-04-02 13:02:40 +00:00
self . builder . add_objects_from_file ( glade_file_path , ( " record_dialog " , ) )
2017-03-01 10:16:03 +00:00
self . dialog = self . builder . get_object ( " record_dialog " )
2017-06-27 21:04:32 +00:00
self . builder . get_object ( " record_dialog " ) . connect ( " key-press-event " , self . on_key_press )
2017-03-01 10:16:03 +00:00
# Set dialog title
2016-01-27 16:23:09 +00:00
if ( index is not None ) :
2017-03-01 10:16:03 +00:00
self . dialog . set_title ( " Edit Record %d " % index )
2016-01-27 16:23:09 +00:00
else :
2017-03-02 09:56:45 +00:00
self . dialog . set_title ( " Add Record " )
2016-01-27 16:23:09 +00:00
# Check if a configuration file is present, since we might need it to set up the rest of the dialog.
config = configparser . ConfigParser ( )
have_config = ( config . read ( expanduser ( ' ~/.config/pyqso/preferences.ini ' ) ) != [ ] )
# Create label:entry pairs and store them in a dictionary
self . sources = { }
2017-03-01 10:16:03 +00:00
# QSO INFORMATION
2016-01-27 16:23:09 +00:00
# CALL
2017-03-01 10:16:03 +00:00
self . sources [ " CALL " ] = self . builder . get_object ( " qso_call_entry " )
self . builder . get_object ( " callsign_lookup " ) . connect ( " clicked " , self . callsign_lookup_callback )
2016-01-27 16:23:09 +00:00
# DATE
2017-03-01 10:16:03 +00:00
self . sources [ " QSO_DATE " ] = self . builder . get_object ( " qso_date_entry " )
self . builder . get_object ( " select_date " ) . connect ( " clicked " , self . calendar_callback )
2016-01-27 16:23:09 +00:00
# TIME
2017-03-01 10:16:03 +00:00
self . sources [ " TIME_ON " ] = self . builder . get_object ( " qso_time_entry " )
self . builder . get_object ( " current_datetime " ) . connect ( " clicked " , self . set_current_datetime_callback )
2016-01-27 16:23:09 +00:00
# FREQ
2017-03-01 10:16:03 +00:00
self . sources [ " FREQ " ] = self . builder . get_object ( " qso_frequency_entry " )
2017-05-07 13:01:28 +00:00
( section , option ) = ( " records " , " default_frequency_unit " )
2017-05-07 00:44:58 +00:00
if ( have_config and config . has_option ( section , option ) ) :
self . frequency_unit = config . get ( section , option )
self . builder . get_object ( " qso_frequency_label " ) . set_label ( " Frequency ( %s ) " % self . frequency_unit )
else :
self . frequency_unit = " MHz "
2016-01-27 16:23:09 +00:00
# BAND
2017-03-01 10:16:03 +00:00
self . sources [ " BAND " ] = self . builder . get_object ( " qso_band_combo " )
2016-01-27 16:23:09 +00:00
for band in BANDS :
self . sources [ " BAND " ] . append_text ( band )
self . sources [ " BAND " ] . set_active ( 0 ) # Set an empty string as the default option.
# MODE
2017-03-01 10:16:03 +00:00
self . sources [ " MODE " ] = self . builder . get_object ( " qso_mode_combo " )
2016-01-27 16:23:09 +00:00
for mode in sorted ( MODES . keys ( ) ) :
self . sources [ " MODE " ] . append_text ( mode )
self . sources [ " MODE " ] . set_active ( 0 ) # Set an empty string as the default option.
2017-04-14 20:45:59 +00:00
self . sources [ " MODE " ] . connect ( " changed " , self . on_mode_changed )
2016-01-27 16:23:09 +00:00
# SUBMODE
2017-03-01 10:16:03 +00:00
self . sources [ " SUBMODE " ] = self . builder . get_object ( " qso_submode_combo " )
2016-01-27 16:23:09 +00:00
self . sources [ " SUBMODE " ] . append_text ( " " )
self . sources [ " SUBMODE " ] . set_active ( 0 ) # Set an empty string initially. As soon as the user selects a particular MODE, the available SUBMODES will appear.
2017-09-04 14:48:50 +00:00
# PROP_MODE
self . sources [ " PROP_MODE " ] = self . builder . get_object ( " qso_propagation_mode_combo " )
for propagation_mode in PROPAGATION_MODES :
self . sources [ " PROP_MODE " ] . append_text ( propagation_mode )
self . sources [ " PROP_MODE " ] . set_active ( 0 ) # Set an empty string as the default option.
2016-01-27 16:23:09 +00:00
# POWER
2017-03-01 10:16:03 +00:00
self . sources [ " TX_PWR " ] = self . builder . get_object ( " qso_power_entry " )
2016-01-27 16:23:09 +00:00
# RST_SENT
2017-03-01 10:16:03 +00:00
self . sources [ " RST_SENT " ] = self . builder . get_object ( " qso_rst_sent_entry " )
2016-01-27 16:23:09 +00:00
# RST_RCVD
2017-03-01 10:16:03 +00:00
self . sources [ " RST_RCVD " ] = self . builder . get_object ( " qso_rst_received_entry " )
2016-01-27 16:23:09 +00:00
# QSL_SENT
2017-03-01 10:16:03 +00:00
self . sources [ " QSL_SENT " ] = self . builder . get_object ( " qso_qsl_sent_combo " )
2017-07-23 15:19:35 +00:00
qsl_sent_options = [ " " , " Y " , " N " , " R " , " Q " , " I " ]
for option in qsl_sent_options :
2016-01-27 16:23:09 +00:00
self . sources [ " QSL_SENT " ] . append_text ( option )
self . sources [ " QSL_SENT " ] . set_active ( 0 ) # Set an empty string as the default option.
# QSL_RCVD
2017-03-01 10:16:03 +00:00
self . sources [ " QSL_RCVD " ] = self . builder . get_object ( " qso_qsl_received_combo " )
2017-07-23 15:19:35 +00:00
qsl_rcvd_options = [ " " , " Y " , " N " , " R " , " I " , " V " ]
for option in qsl_rcvd_options :
2016-01-27 16:23:09 +00:00
self . sources [ " QSL_RCVD " ] . append_text ( option )
self . sources [ " QSL_RCVD " ] . set_active ( 0 ) # Set an empty string as the default option.
# NOTES
2017-03-01 10:16:03 +00:00
self . sources [ " NOTES " ] = self . builder . get_object ( " qso_notes_textview " ) . get_buffer ( )
# STATION INFORMATION
2016-01-27 16:23:09 +00:00
# NAME
2017-03-01 10:16:03 +00:00
self . sources [ " NAME " ] = self . builder . get_object ( " station_name_entry " )
2016-01-27 16:23:09 +00:00
# ADDRESS
2017-03-01 10:16:03 +00:00
self . sources [ " ADDRESS " ] = self . builder . get_object ( " station_address_entry " )
2016-01-27 16:23:09 +00:00
# STATE
2017-03-01 10:16:03 +00:00
self . sources [ " STATE " ] = self . builder . get_object ( " station_state_entry " )
2016-01-27 16:23:09 +00:00
# COUNTRY
2017-03-01 10:16:03 +00:00
self . sources [ " COUNTRY " ] = self . builder . get_object ( " station_country_entry " )
2016-01-27 16:23:09 +00:00
# DXCC
2017-03-01 10:16:03 +00:00
self . sources [ " DXCC " ] = self . builder . get_object ( " station_dxcc_entry " )
2016-01-27 16:23:09 +00:00
# CQZ
2017-03-01 10:16:03 +00:00
self . sources [ " CQZ " ] = self . builder . get_object ( " station_cq_entry " )
2016-01-27 16:23:09 +00:00
# ITUZ
2017-03-01 10:16:03 +00:00
self . sources [ " ITUZ " ] = self . builder . get_object ( " station_itu_entry " )
2016-01-27 16:23:09 +00:00
# IOTA
2017-03-01 10:16:03 +00:00
self . sources [ " IOTA " ] = self . builder . get_object ( " station_iota_entry " )
2016-01-27 16:23:09 +00:00
2017-09-04 14:48:50 +00:00
# GRIDSQUARE
self . sources [ " GRIDSQUARE " ] = self . builder . get_object ( " station_gridsquare_entry " )
# SATELLITE INFORMATION
# SAT_NAME
self . sources [ " SAT_NAME " ] = self . builder . get_object ( " satellite_name_entry " )
# SAT_MODE
self . sources [ " SAT_MODE " ] = self . builder . get_object ( " satellite_mode_entry " )
2016-01-27 16:23:09 +00:00
# Populate various fields, if possible.
if ( index is not None ) :
# The record already exists, so display its current data in the input boxes.
record = log . get_record_by_index ( index )
field_names = AVAILABLE_FIELD_NAMES_ORDERED
for i in range ( 0 , len ( field_names ) ) :
data = record [ field_names [ i ] . lower ( ) ]
if ( data is None ) :
data = " "
if ( field_names [ i ] == " BAND " ) :
self . sources [ field_names [ i ] ] . set_active ( BANDS . index ( data ) )
2017-05-07 00:44:58 +00:00
elif ( field_names [ i ] == " FREQ " and self . frequency_unit != " MHz " ) :
converted = self . convert_frequency ( data , from_unit = " MHz " , to_unit = self . frequency_unit )
self . sources [ field_names [ i ] ] . set_text ( str ( converted ) )
2016-01-27 16:23:09 +00:00
elif ( field_names [ i ] == " MODE " ) :
self . sources [ field_names [ i ] ] . set_active ( sorted ( MODES . keys ( ) ) . index ( data ) )
2017-05-07 00:44:58 +00:00
# Handle SUBMODE at the same time.
2016-01-27 16:23:09 +00:00
submode_data = record [ " submode " ]
if ( submode_data is None ) :
submode_data = " "
self . sources [ " SUBMODE " ] . set_active ( MODES [ data ] . index ( submode_data ) )
elif ( field_names [ i ] == " SUBMODE " ) :
2017-05-07 00:44:58 +00:00
# Skip, because this has been (or will be) handled when populating the MODE field.
2016-01-27 16:23:09 +00:00
continue
2017-09-04 14:48:50 +00:00
elif ( field_names [ i ] == " PROP_MODE " ) :
self . sources [ field_names [ i ] ] . set_active ( PROPAGATION_MODES . index ( data ) )
2017-07-23 15:19:35 +00:00
elif ( field_names [ i ] == " QSL_SENT " ) :
self . sources [ field_names [ i ] ] . set_active ( qsl_sent_options . index ( data ) )
elif ( field_names [ i ] == " QSL_RCVD " ) :
self . sources [ field_names [ i ] ] . set_active ( qsl_rcvd_options . index ( data ) )
2016-01-27 16:23:09 +00:00
else :
self . sources [ field_names [ i ] ] . set_text ( data )
else :
# Automatically fill in the current date and time
self . set_current_datetime_callback ( )
# Set up default field values
# Mode
( section , option ) = ( " records " , " default_mode " )
if ( have_config and config . has_option ( section , option ) ) :
mode = config . get ( section , option )
else :
mode = " "
self . sources [ " MODE " ] . set_active ( sorted ( MODES . keys ( ) ) . index ( mode ) )
# Submode
( section , option ) = ( " records " , " default_submode " )
if ( have_config and config . has_option ( section , option ) ) :
submode = config . get ( section , option )
else :
submode = " "
self . sources [ " SUBMODE " ] . set_active ( MODES [ mode ] . index ( submode ) )
# Power
( section , option ) = ( " records " , " default_power " )
if ( have_config and config . has_option ( section , option ) ) :
power = config . get ( section , option )
2013-03-26 02:42:13 +00:00
else :
2016-01-27 16:23:09 +00:00
power = " "
self . sources [ " TX_PWR " ] . set_text ( power )
2017-02-07 15:31:16 +00:00
# If the Hamlib module is present, then use it to fill in various fields if desired.
2016-01-27 16:23:09 +00:00
if ( have_hamlib ) :
if ( have_config and config . has_option ( " hamlib " , " autofill " ) and config . has_option ( " hamlib " , " rig_model " ) and config . has_option ( " hamlib " , " rig_pathname " ) ) :
2017-07-09 10:42:42 +00:00
autofill = ( config . getboolean ( " hamlib " , " autofill " ) )
2016-01-27 16:23:09 +00:00
rig_model = config . get ( " hamlib " , " rig_model " )
rig_pathname = config . get ( " hamlib " , " rig_pathname " )
if ( autofill ) :
2017-04-14 20:45:59 +00:00
self . hamlib_autofill ( rig_model , rig_pathname )
2016-01-27 16:23:09 +00:00
# Do we want PyQSO to autocomplete the Band field based on the Frequency field?
( section , option ) = ( " records " , " autocomplete_band " )
2017-02-07 16:24:16 +00:00
if ( have_config and config . has_option ( section , option ) ) :
2017-07-09 10:42:42 +00:00
autocomplete_band = ( config . getboolean ( section , option ) )
2016-01-27 16:23:09 +00:00
if ( autocomplete_band ) :
2017-04-14 20:45:59 +00:00
self . sources [ " FREQ " ] . connect ( " changed " , self . autocomplete_band )
2016-01-27 16:23:09 +00:00
else :
# If no configuration file exists, autocomplete the Band field by default.
2017-04-14 20:45:59 +00:00
self . sources [ " FREQ " ] . connect ( " changed " , self . autocomplete_band )
2016-01-27 16:23:09 +00:00
2017-03-01 10:16:03 +00:00
self . dialog . show_all ( )
2016-01-27 16:23:09 +00:00
logging . debug ( " Record dialog ready! " )
return
def get_data ( self , field_name ) :
""" 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.
return self . sources [ field_name ] . get_text ( ) . upper ( )
2017-05-07 00:44:58 +00:00
elif ( field_name == " FREQ " and self . frequency_unit != " MHz " ) :
converted = self . convert_frequency ( self . sources [ field_name ] . get_text ( ) , from_unit = self . frequency_unit , to_unit = " MHz " )
return str ( converted )
2016-01-27 16:23:09 +00:00
elif ( field_name == " MODE " ) :
return self . sources [ " MODE " ] . get_active_text ( )
elif ( field_name == " SUBMODE " ) :
return self . sources [ " SUBMODE " ] . get_active_text ( )
2017-09-04 14:48:50 +00:00
elif ( field_name == " PROP_MODE " ) :
return self . sources [ " PROP_MODE " ] . get_active_text ( )
2016-01-27 16:23:09 +00:00
elif ( field_name == " BAND " or field_name == " QSL_SENT " or field_name == " QSL_RCVD " ) :
return self . sources [ field_name ] . get_active_text ( )
elif ( field_name == " NOTES " ) :
( start , end ) = self . sources [ field_name ] . get_bounds ( )
text = self . sources [ field_name ] . get_text ( start , end , True )
return text
else :
return self . sources [ field_name ] . get_text ( )
2017-04-14 20:45:59 +00:00
def on_mode_changed ( self , combo ) :
2016-01-27 16:23:09 +00:00
""" If the MODE field has changed its value, then fill the SUBMODE field with all the available SUBMODE options for that new MODE. """
self . sources [ " SUBMODE " ] . get_model ( ) . clear ( )
2017-04-24 16:01:18 +00:00
mode = combo . get_active_text ( )
for submode in MODES [ mode ] :
2016-01-27 16:23:09 +00:00
self . sources [ " SUBMODE " ] . append_text ( submode )
2017-04-24 16:01:18 +00:00
self . sources [ " SUBMODE " ] . set_active ( MODES [ mode ] . index ( " " ) ) # Set the submode to an empty string.
2016-01-27 16:23:09 +00:00
return
2017-06-27 21:04:32 +00:00
def on_key_press ( self , widget , event ) :
2017-03-02 10:45:49 +00:00
""" If the Return key is pressed, emit the " OK " response to record the QSO. """
child = widget . get_focus ( )
if ( not ( isinstance ( child , Gtk . ToggleButton ) or isinstance ( child , Gtk . Button ) or isinstance ( child , Gtk . TextView ) ) and event . keyval == Gdk . KEY_Return ) :
self . dialog . emit ( ' response ' , Gtk . ResponseType . OK )
return
2017-04-14 20:45:59 +00:00
def autocomplete_band ( self , widget = None ) :
2016-01-27 16:23:09 +00:00
""" If a value for the Frequency is entered, this function autocompletes the Band field. """
frequency = self . sources [ " FREQ " ] . get_text ( )
2017-05-07 00:44:58 +00:00
2016-01-27 16:23:09 +00:00
# Check whether we actually have a (valid) value to use. If not, set the BAND field to an empty string ("").
try :
frequency = float ( frequency )
except ValueError :
self . sources [ " BAND " ] . set_active ( 0 )
2014-03-23 17:11:11 +00:00
return
2014-03-23 01:24:45 +00:00
2017-05-07 00:44:58 +00:00
# Convert to MHz if necessary.
if ( self . frequency_unit != " MHz " ) :
frequency = self . convert_frequency ( frequency , from_unit = self . frequency_unit , to_unit = " MHz " )
2016-01-27 16:23:09 +00:00
# Find which band the frequency lies in.
for i in range ( 1 , len ( BANDS ) ) :
if ( frequency > = BANDS_RANGES [ i ] [ 0 ] and frequency < = BANDS_RANGES [ i ] [ 1 ] ) :
self . sources [ " BAND " ] . set_active ( i )
return
self . sources [ " BAND " ] . set_active ( 0 ) # If we've reached this, then the frequency does not lie in any of the specified bands.
return
2017-04-14 20:45:59 +00:00
def hamlib_autofill ( self , rig_model , rig_pathname ) :
2017-02-07 15:54:34 +00:00
""" Set the various fields using data from the radio via Hamlib.
: arg str rig_model : The model of the radio / rig .
: arg str rig_pathname : The path to the rig ( or rig control device ) .
"""
# Open a communication channel to the radio.
try :
Hamlib . rig_set_debug ( Hamlib . RIG_DEBUG_NONE )
2017-06-24 17:12:27 +00:00
rig = Hamlib . Rig ( Hamlib . __dict__ [ rig_model ] ) # Look up the model's numerical index in Hamlib's symbol dictionary.
2017-02-07 15:54:34 +00:00
rig . set_conf ( " rig_pathname " , rig_pathname )
rig . open ( )
except :
logging . error ( " Could not open a communication channel to the rig via Hamlib! " )
return
# Frequency
try :
2017-06-24 17:12:27 +00:00
frequency = " %.6f " % ( rig . get_freq ( ) / 1.0e6 ) # Converting to MHz here.
2017-05-07 00:44:58 +00:00
# Convert to the desired unit, if necessary.
if ( self . frequency_unit != " MHz " ) :
frequency = str ( self . convert_frequency ( frequency , from_unit = " MHz " , to_unit = self . frequency_unit ) )
2017-02-07 15:54:34 +00:00
self . sources [ " FREQ " ] . set_text ( frequency )
except :
logging . error ( " Could not obtain the current frequency via Hamlib! " )
# Mode
try :
( mode , width ) = rig . get_mode ( )
2017-06-24 17:12:27 +00:00
mode = Hamlib . rig_strrmode ( mode ) . upper ( )
2017-02-07 15:54:34 +00:00
# Handle USB and LSB as special cases.
if ( mode == " USB " or mode == " LSB " ) :
submode = mode
mode = " SSB "
self . sources [ " MODE " ] . set_active ( sorted ( MODES . keys ( ) ) . index ( mode ) )
self . sources [ " SUBMODE " ] . set_active ( MODES [ mode ] . index ( submode ) )
else :
self . sources [ " MODE " ] . set_active ( sorted ( MODES . keys ( ) ) . index ( mode ) )
except :
logging . error ( " Could not obtain the current mode (e.g. FM, AM, CW) via Hamlib! " )
# Close communication channel.
try :
rig . close ( )
except :
logging . error ( " Could not close the communication channel to the rig via Hamlib! " )
2017-06-24 17:56:46 +00:00
return
2017-02-07 15:54:34 +00:00
2017-03-01 10:16:03 +00:00
def callsign_lookup_callback ( self , widget = None ) :
2016-01-27 16:23:09 +00:00
""" Get the callsign-related data from an online database and store it in the relevant Gtk.Entry boxes, but return None. """
# Get the database name.
config = configparser . ConfigParser ( )
have_config = ( config . read ( expanduser ( ' ~/.config/pyqso/preferences.ini ' ) ) != [ ] )
try :
if ( have_config and config . has_option ( " records " , " callsign_database " ) ) :
database = config . get ( " records " , " callsign_database " )
if ( database == " " ) :
raise ValueError
else :
raise ValueError
except ValueError :
2017-03-02 10:14:21 +00:00
error ( parent = self . dialog , message = " To perform a callsign lookup, please specify the name of the callsign database in the Preferences. " )
2016-01-27 16:23:09 +00:00
return
try :
if ( database == " qrz.com " ) :
# QRZ.com
2017-04-20 22:55:56 +00:00
callsign_lookup = CallsignLookupQRZ ( parent = self . dialog )
2016-01-27 16:23:09 +00:00
elif ( database == " hamqth.com " ) :
2017-06-24 17:04:21 +00:00
# HamQTH.com
2017-04-20 22:55:56 +00:00
callsign_lookup = CallsignLookupHamQTH ( parent = self . dialog )
2016-01-27 16:23:09 +00:00
else :
raise ValueError ( " Unknown callsign database: %s " % database )
except ValueError as e :
logging . exception ( e )
2017-07-03 21:35:28 +00:00
error ( parent = self . dialog , message = e )
2016-01-27 16:23:09 +00:00
return
2017-07-07 11:22:18 +00:00
# Get username and password from configuration file.
2016-01-27 16:23:09 +00:00
if ( have_config and config . has_option ( " records " , " callsign_database_username " ) and config . has_option ( " records " , " callsign_database_password " ) ) :
username = config . get ( " records " , " callsign_database_username " )
password = base64 . b64decode ( config . get ( " records " , " callsign_database_password " ) ) . decode ( " utf-8 " )
2017-07-06 20:06:04 +00:00
if ( not username or not password ) :
2016-01-27 16:23:09 +00:00
details_given = False
else :
details_given = True
else :
2013-07-13 19:23:53 +00:00
details_given = False
2016-01-27 16:23:09 +00:00
if ( not details_given ) :
2017-03-02 10:14:21 +00:00
error ( parent = self . dialog , message = " To perform a callsign lookup, please specify your username and password in the Preferences. " )
2016-01-27 16:23:09 +00:00
return
2017-07-07 11:22:18 +00:00
# Get the callsign from the CALL field.
full_callsign = self . sources [ " CALL " ] . get_text ( )
if ( not full_callsign ) :
# Empty callsign field.
error ( parent = self . dialog , message = " Please enter a callsign to lookup. " )
return
# Connect to the database.
2016-01-27 16:23:09 +00:00
connected = callsign_lookup . connect ( username , password )
if ( connected ) :
# Check whether we want to ignore any prefixes (e.g. "IA/") or suffixes "(e.g. "/M") in the callsign
# before performing the lookup.
if ( have_config and config . has_option ( " records " , " ignore_prefix_suffix " ) ) :
2017-07-09 10:42:42 +00:00
ignore_prefix_suffix = ( config . getboolean ( " records " , " ignore_prefix_suffix " ) )
2016-01-27 16:23:09 +00:00
else :
ignore_prefix_suffix = True
2017-07-07 11:22:18 +00:00
# Perform the lookup.
2016-01-27 16:23:09 +00:00
fields_and_data = callsign_lookup . lookup ( full_callsign , ignore_prefix_suffix = ignore_prefix_suffix )
for field_name in list ( fields_and_data . keys ( ) ) :
self . sources [ field_name ] . set_text ( fields_and_data [ field_name ] )
return
def calendar_callback ( self , widget ) :
""" Open up a calendar widget for easy QSO_DATE selection. Return None after the user destroys the dialog. """
2017-03-31 09:06:11 +00:00
c = CalendarDialog ( self . application )
2017-02-24 00:04:40 +00:00
response = c . dialog . run ( )
2016-01-27 16:23:09 +00:00
if ( response == Gtk . ResponseType . OK ) :
2017-02-24 00:04:40 +00:00
self . sources [ " QSO_DATE " ] . set_text ( c . date )
c . dialog . destroy ( )
2016-01-27 16:23:09 +00:00
return
def set_current_datetime_callback ( self , widget = None ) :
""" Insert the current date and time. """
# Check if a configuration file is present.
config = configparser . ConfigParser ( )
have_config = ( config . read ( expanduser ( ' ~/.config/pyqso/preferences.ini ' ) ) != [ ] )
# Do we want to use UTC or the computer's local time?
( section , option ) = ( " records " , " use_utc " )
if ( have_config and config . has_option ( section , option ) ) :
2017-07-09 10:42:42 +00:00
use_utc = ( config . getboolean ( section , option ) )
2016-01-27 16:23:09 +00:00
if ( use_utc ) :
dt = datetime . utcnow ( )
else :
dt = datetime . now ( )
else :
dt = datetime . utcnow ( ) # Use UTC by default, since this is expected by ADIF.
self . sources [ " QSO_DATE " ] . set_text ( dt . strftime ( " % Y % m %d " ) )
self . sources [ " TIME_ON " ] . set_text ( dt . strftime ( " % H % M " ) )
return
2017-05-07 00:44:58 +00:00
def convert_frequency ( self , frequency , from_unit , to_unit ) :
""" Convert a frequency from one unit to another.
: arg float frequency : The frequency to convert .
: arg str from_unit : The current unit of the frequency .
: arg str to_unit : The desired unit of the frequency .
: rtype : float
: returns : The frequency in the to_unit .
"""
scaling = { " Hz " : 1 , " kHz " : 1e3 , " MHz " : 1e6 , " GHz " : 1e9 }
# Check that the from/to frequency units are valid.
try :
if ( from_unit not in scaling . keys ( ) ) :
raise ValueError ( " Unknown frequency unit ' %s ' in from_unit " % from_unit )
if ( to_unit not in scaling . keys ( ) ) :
raise ValueError ( " Unknown frequency unit ' %s ' in to_unit " % to_unit )
except ValueError as e :
logging . exception ( e )
return frequency
# Cast to float before scaling.
if ( not isinstance ( frequency , float ) ) :
try :
2017-07-02 13:56:39 +00:00
if ( frequency == " " or frequency is None ) :
return frequency
else :
frequency = float ( frequency )
2017-07-02 13:54:42 +00:00
except ( ValueError , TypeError ) :
2017-05-07 00:44:58 +00:00
logging . exception ( " Could not convert frequency to a floating-point value. " )
return frequency
# Do not bother scaling if the units are the same.
if ( from_unit == to_unit ) :
return frequency
coefficient = scaling [ from_unit ] / scaling [ to_unit ]
return float ( " %.6f " % ( coefficient * frequency ) )