not1mm 25.5.26.1__py3-none-any.whl → 25.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- not1mm/__main__.py +66 -43
- not1mm/data/MASTER.SCP +2636 -2654
- not1mm/data/cty.json +1 -1
- not1mm/data/new_contest.ui +5 -0
- not1mm/lib/database.py +14 -45
- not1mm/lib/edit_station.py +5 -5
- not1mm/lib/plugin_common.py +21 -0
- not1mm/lib/super_check_partial.py +28 -12
- not1mm/lib/version.py +1 -1
- not1mm/logwindow.py +4 -0
- not1mm/plugins/ari_dx.py +11 -11
- not1mm/plugins/arrl_160m.py +13 -13
- not1mm/plugins/arrl_dx_cw.py +47 -47
- not1mm/plugins/arrl_dx_ssb.py +48 -48
- not1mm/plugins/canada_day.py +6 -6
- not1mm/plugins/cq_160_cw.py +16 -16
- not1mm/plugins/cq_160_ssb.py +16 -16
- not1mm/plugins/cq_wpx_cw.py +28 -28
- not1mm/plugins/cq_wpx_rtty.py +20 -20
- not1mm/plugins/cq_wpx_ssb.py +28 -28
- not1mm/plugins/cq_ww_cw.py +19 -19
- not1mm/plugins/cq_ww_rtty.py +14 -14
- not1mm/plugins/cq_ww_ssb.py +18 -18
- not1mm/plugins/ea_majistad_cw.py +6 -6
- not1mm/plugins/ea_majistad_ssb.py +6 -6
- not1mm/plugins/ea_rtty.py +6 -6
- not1mm/plugins/es_field_day.py +604 -0
- not1mm/plugins/es_open.py +37 -26
- not1mm/plugins/helvetia.py +12 -12
- not1mm/plugins/iaru_hf.py +3 -3
- not1mm/plugins/jidx_cw.py +4 -4
- not1mm/plugins/jidx_ph.py +4 -4
- not1mm/plugins/lz-dx.py +12 -12
- not1mm/plugins/naqp_cw.py +6 -6
- not1mm/plugins/naqp_rtty.py +6 -6
- not1mm/plugins/naqp_ssb.py +6 -6
- not1mm/plugins/phone_weekly_test.py +6 -6
- not1mm/plugins/ref_cw.py +8 -8
- not1mm/plugins/ref_ssb.py +8 -8
- not1mm/plugins/sac_cw.py +9 -9
- not1mm/plugins/sac_ssb.py +11 -11
- not1mm/plugins/spdx.py +7 -7
- not1mm/plugins/ukeidx.py +10 -10
- not1mm/statistics.py +1 -0
- {not1mm-25.5.26.1.dist-info → not1mm-25.6.1.dist-info}/METADATA +7 -277
- {not1mm-25.5.26.1.dist-info → not1mm-25.6.1.dist-info}/RECORD +50 -49
- {not1mm-25.5.26.1.dist-info → not1mm-25.6.1.dist-info}/WHEEL +1 -1
- {not1mm-25.5.26.1.dist-info → not1mm-25.6.1.dist-info}/entry_points.txt +0 -0
- {not1mm-25.5.26.1.dist-info → not1mm-25.6.1.dist-info}/licenses/LICENSE +0 -0
- {not1mm-25.5.26.1.dist-info → not1mm-25.6.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,604 @@
|
|
1
|
+
""" """
|
2
|
+
|
3
|
+
import logging
|
4
|
+
import platform
|
5
|
+
from datetime import datetime
|
6
|
+
from datetime import timedelta
|
7
|
+
from datetime import timezone
|
8
|
+
|
9
|
+
from pathlib import Path
|
10
|
+
|
11
|
+
from PyQt6 import QtWidgets
|
12
|
+
|
13
|
+
from not1mm.lib.plugin_common import gen_adif, get_points, get_station_state_code, get_station_arrlsection_code
|
14
|
+
|
15
|
+
from not1mm.lib.ham_utility import calculate_wpx_prefix
|
16
|
+
from not1mm.lib.version import __version__
|
17
|
+
|
18
|
+
logger = logging.getLogger(__name__)
|
19
|
+
|
20
|
+
EXCHANGE_HINT = "#"
|
21
|
+
|
22
|
+
name = "ES FIELD DAY"
|
23
|
+
cabrillo_name = "ES-FIELD-DAY"
|
24
|
+
mode = "BOTH" # CW SSB BOTH RTTY
|
25
|
+
|
26
|
+
columns = [
|
27
|
+
"YYYY-MM-DD HH:MM:SS",
|
28
|
+
"Call",
|
29
|
+
"Freq",
|
30
|
+
"Mode",
|
31
|
+
"Snt",
|
32
|
+
"Rcv",
|
33
|
+
"SentNr",
|
34
|
+
"RcvNr",
|
35
|
+
"PTS",
|
36
|
+
]
|
37
|
+
|
38
|
+
advance_on_space = [True, True, True, True, True]
|
39
|
+
|
40
|
+
# 5 Contest specific dupe check.
|
41
|
+
dupe_type = 5
|
42
|
+
|
43
|
+
estonian_regions = [
|
44
|
+
"HM",
|
45
|
+
"HR",
|
46
|
+
"IV",
|
47
|
+
"JG",
|
48
|
+
"JR",
|
49
|
+
"LN",
|
50
|
+
"LV",
|
51
|
+
"PL",
|
52
|
+
"PU",
|
53
|
+
"RP",
|
54
|
+
"SR",
|
55
|
+
"TA",
|
56
|
+
"TL",
|
57
|
+
"VC",
|
58
|
+
"VO",
|
59
|
+
"VP"
|
60
|
+
]
|
61
|
+
|
62
|
+
def specific_contest_check_dupe(self, call):
|
63
|
+
""""""
|
64
|
+
# get mode from radio state
|
65
|
+
mode = self.radio_state.get("mode", "")
|
66
|
+
"""Dupe checking specific to just this contest."""
|
67
|
+
# constant to split the contest - correct ES Open Contest length is 4 hours
|
68
|
+
contest_length_in_minutes = 90
|
69
|
+
split_contest_by_minutes = 30
|
70
|
+
|
71
|
+
period_count = int(contest_length_in_minutes / split_contest_by_minutes)
|
72
|
+
|
73
|
+
# think about generic solution by splitting the contest to n different periods
|
74
|
+
start_date_init = self.contest_settings.get("StartDate", "")
|
75
|
+
start_date_init_date = datetime.strptime(start_date_init, "%Y-%m-%d %H:%M:%S")
|
76
|
+
|
77
|
+
# Create time periods dynamically based on period count
|
78
|
+
time_periods = []
|
79
|
+
for i in range(period_count):
|
80
|
+
minutes_to_add = split_contest_by_minutes * (i + 1)
|
81
|
+
time_period = start_date_init_date + timedelta(minutes=minutes_to_add)
|
82
|
+
time_periods.append(time_period)
|
83
|
+
|
84
|
+
# Assign to variables for backwards compatibility
|
85
|
+
time_period_1 = time_periods[0] if len(time_periods) > 0 else None
|
86
|
+
time_period_2 = time_periods[1] if len(time_periods) > 1 else None
|
87
|
+
time_period_3 = time_periods[2] if len(time_periods) > 2 else None
|
88
|
+
|
89
|
+
# get current time in UTC
|
90
|
+
iso_current_time = datetime.now(timezone.utc)
|
91
|
+
current_time = iso_current_time.replace(tzinfo=None)
|
92
|
+
|
93
|
+
result = {}
|
94
|
+
result["isdupe"] = False
|
95
|
+
|
96
|
+
if current_time < time_period_1 and current_time >= start_date_init_date:
|
97
|
+
|
98
|
+
result = self.database.check_dupe_on_period_mode(
|
99
|
+
call,
|
100
|
+
self.contact.get("Band", ""),
|
101
|
+
mode,
|
102
|
+
start_date_init_date,
|
103
|
+
time_period_1.strftime("%Y-%m-%d %H:%M:%S"),
|
104
|
+
)
|
105
|
+
|
106
|
+
if current_time < time_period_2 and current_time >= time_period_1:
|
107
|
+
|
108
|
+
result = self.database.check_dupe_on_period_mode(
|
109
|
+
call,
|
110
|
+
self.contact.get("Band", ""),
|
111
|
+
mode,
|
112
|
+
time_period_1.strftime("%Y-%m-%d %H:%M:%S"),
|
113
|
+
time_period_2.strftime("%Y-%m-%d %H:%M:%S"),
|
114
|
+
)
|
115
|
+
|
116
|
+
if current_time < time_period_3 and current_time >= time_period_2:
|
117
|
+
|
118
|
+
result = self.database.check_dupe_on_period_mode(
|
119
|
+
call,
|
120
|
+
self.contact.get("Band", ""),
|
121
|
+
mode,
|
122
|
+
time_period_2.strftime("%Y-%m-%d %H:%M:%S"),
|
123
|
+
time_period_3.strftime("%Y-%m-%d %H:%M:%S"),
|
124
|
+
)
|
125
|
+
|
126
|
+
# just for band and mode if outside of time period
|
127
|
+
else:
|
128
|
+
result = self.database.check_dupe_on_band_mode(
|
129
|
+
call, self.contact.get("Band", ""), mode
|
130
|
+
)
|
131
|
+
|
132
|
+
return result
|
133
|
+
|
134
|
+
def init_contest(self):
|
135
|
+
"""setup plugin"""
|
136
|
+
set_tab_next(self)
|
137
|
+
set_tab_prev(self)
|
138
|
+
interface(self)
|
139
|
+
self.next_field = self.other_2
|
140
|
+
|
141
|
+
|
142
|
+
def interface(self):
|
143
|
+
"""Setup user interface"""
|
144
|
+
"""Setup user interface"""
|
145
|
+
self.field1.show()
|
146
|
+
self.field2.show()
|
147
|
+
self.field3.show()
|
148
|
+
self.field4.show()
|
149
|
+
self.other_label.setText("Sent")
|
150
|
+
self.field3.setAccessibleName("Sent")
|
151
|
+
self.exch_label.setText("SN")
|
152
|
+
self.field4.setAccessibleName("SN")
|
153
|
+
|
154
|
+
|
155
|
+
def reset_label(self):
|
156
|
+
"""reset label after field cleared"""
|
157
|
+
|
158
|
+
|
159
|
+
def set_tab_next(self):
|
160
|
+
"""Set TAB Advances"""
|
161
|
+
self.tab_next = {
|
162
|
+
self.callsign: self.other_1,
|
163
|
+
self.sent: self.other_1,
|
164
|
+
self.receive: self.other_1,
|
165
|
+
self.other_1: self.other_2,
|
166
|
+
self.other_2: self.callsign,
|
167
|
+
}
|
168
|
+
|
169
|
+
|
170
|
+
def set_tab_prev(self):
|
171
|
+
"""Set TAB Advances"""
|
172
|
+
self.tab_prev = {
|
173
|
+
self.callsign: self.other_2,
|
174
|
+
self.sent: self.callsign,
|
175
|
+
self.receive: self.callsign,
|
176
|
+
self.other_1: self.callsign,
|
177
|
+
self.other_2: self.other_1,
|
178
|
+
}
|
179
|
+
|
180
|
+
|
181
|
+
def set_contact_vars(self):
|
182
|
+
"""Contest Specific"""
|
183
|
+
self.contact["SNT"] = self.sent.text()
|
184
|
+
self.contact["RCV"] = self.receive.text()
|
185
|
+
self.contact["SentNr"] = self.other_1.text().upper()
|
186
|
+
self.contact["NR"] = self.other_2.text().upper()
|
187
|
+
|
188
|
+
self.contact["IsMultiplier1"] = 0
|
189
|
+
self.contact["IsMultiplier2"] = 0
|
190
|
+
|
191
|
+
|
192
|
+
def predupe(self):
|
193
|
+
"""called after callsign entered"""
|
194
|
+
|
195
|
+
|
196
|
+
def prefill(self):
|
197
|
+
"""Fill SentNR"""
|
198
|
+
|
199
|
+
sent_sxchange_setting = self.contest_settings.get("SentExchange", "")
|
200
|
+
if sent_sxchange_setting.strip() == "#":
|
201
|
+
result = self.database.get_serial()
|
202
|
+
serial_nr = str(result.get("serial_nr", "1")).zfill(3)
|
203
|
+
# get station region code from setup ARRLSection field
|
204
|
+
serial_nr = serial_nr + " " + get_station_state_code(self)
|
205
|
+
|
206
|
+
if serial_nr == "None":
|
207
|
+
serial_nr = "001"
|
208
|
+
if len(self.other_1.text()) == 0:
|
209
|
+
self.other_1.setText(serial_nr)
|
210
|
+
else:
|
211
|
+
self.other_1.setText(sent_sxchange_setting)
|
212
|
+
|
213
|
+
|
214
|
+
def points(self):
|
215
|
+
""" """
|
216
|
+
if self.contact_is_dupe > 0:
|
217
|
+
return 0
|
218
|
+
|
219
|
+
# get received number and region code
|
220
|
+
|
221
|
+
check_call = self.contact.get("Call", "")
|
222
|
+
# all stations with /p give 3 points
|
223
|
+
if "/p" in check_call.lower():
|
224
|
+
return 3
|
225
|
+
# all stations with /qrp give 5 points
|
226
|
+
elif "/qrp" in check_call.lower():
|
227
|
+
return 5
|
228
|
+
else:
|
229
|
+
return 1
|
230
|
+
|
231
|
+
def show_mults(self, rtc=None):
|
232
|
+
"""Return display string for mults"""
|
233
|
+
|
234
|
+
# implement here multipliers checks
|
235
|
+
# get received number and region code
|
236
|
+
|
237
|
+
call_result = str(self.contact.get("NR", ""))
|
238
|
+
# create placeholders
|
239
|
+
placeholders = ','.join(['?'] * len(estonian_regions))
|
240
|
+
# main query to filter by regions
|
241
|
+
query = f"SELECT count(distinct(SUBSTR(NR, -2)) || ':' || Band || ':' || Mode) as mults from DXLOG where ContestNR = {self.pref.get('contest', '1')} AND CountryPrefix = 'ES' AND NR GLOB '*[A-Z]*' AND substr(NR,-2) IN ({placeholders});"
|
242
|
+
# apply params
|
243
|
+
params = estonian_regions
|
244
|
+
# run query
|
245
|
+
result = self.database.exec_sql_params_mult(query, params)
|
246
|
+
if result:
|
247
|
+
mult_count = result.get("mults", 0)
|
248
|
+
return mult_count
|
249
|
+
return 0
|
250
|
+
|
251
|
+
def show_qso(self):
|
252
|
+
"""Return qso count"""
|
253
|
+
result = self.database.fetch_qso_count()
|
254
|
+
if result:
|
255
|
+
return int(result.get("qsos", 0))
|
256
|
+
return 0
|
257
|
+
|
258
|
+
|
259
|
+
def calc_score(self):
|
260
|
+
"""Return calculated score"""
|
261
|
+
result = self.database.fetch_points()
|
262
|
+
if result is not None:
|
263
|
+
score = result.get("Points", "0")
|
264
|
+
if score is None:
|
265
|
+
score = "0"
|
266
|
+
contest_points = int(score)
|
267
|
+
mults = show_mults(self)
|
268
|
+
return contest_points * (mults + 1)
|
269
|
+
return 0
|
270
|
+
|
271
|
+
|
272
|
+
def recalculate_mults(self):
|
273
|
+
"""Recalculates multipliers after change in logged qso."""
|
274
|
+
|
275
|
+
|
276
|
+
def adif(self):
|
277
|
+
"""Call the generate ADIF function"""
|
278
|
+
gen_adif(self, cabrillo_name, "ES OPEN")
|
279
|
+
|
280
|
+
|
281
|
+
def output_cabrillo_line(line_to_output, ending, file_descriptor, file_encoding):
|
282
|
+
""""""
|
283
|
+
print(
|
284
|
+
line_to_output.encode(file_encoding, errors="ignore").decode(),
|
285
|
+
end=ending,
|
286
|
+
file=file_descriptor,
|
287
|
+
)
|
288
|
+
|
289
|
+
|
290
|
+
def cabrillo(self, file_encoding):
|
291
|
+
"""Generates Cabrillo file. Maybe."""
|
292
|
+
# https://www.cqwpx.com/cabrillo.htm
|
293
|
+
logger.debug("******Cabrillo*****")
|
294
|
+
logger.debug("Station: %s", f"{self.station}")
|
295
|
+
logger.debug("Contest: %s", f"{self.contest_settings}")
|
296
|
+
now = datetime.now()
|
297
|
+
date_time = now.strftime("%Y-%m-%d_%H-%M-%S")
|
298
|
+
filename = (
|
299
|
+
str(Path.home())
|
300
|
+
+ "/"
|
301
|
+
+ f"{self.station.get('Call', '').upper()}_{cabrillo_name}_{date_time}.log"
|
302
|
+
)
|
303
|
+
logger.debug("%s", filename)
|
304
|
+
log = self.database.fetch_all_contacts_asc()
|
305
|
+
try:
|
306
|
+
with open(filename, "w", encoding=file_encoding, newline="") as file_descriptor:
|
307
|
+
output_cabrillo_line(
|
308
|
+
"START-OF-LOG: 3.0",
|
309
|
+
"\r\n",
|
310
|
+
file_descriptor,
|
311
|
+
file_encoding,
|
312
|
+
)
|
313
|
+
output_cabrillo_line(
|
314
|
+
f"CREATED-BY: Not1MM v{__version__}",
|
315
|
+
"\r\n",
|
316
|
+
file_descriptor,
|
317
|
+
file_encoding,
|
318
|
+
)
|
319
|
+
output_cabrillo_line(
|
320
|
+
f"CONTEST: {cabrillo_name}",
|
321
|
+
"\r\n",
|
322
|
+
file_descriptor,
|
323
|
+
file_encoding,
|
324
|
+
)
|
325
|
+
if self.station.get("Club", ""):
|
326
|
+
output_cabrillo_line(
|
327
|
+
f"CLUB: {self.station.get('Club', '').upper()}",
|
328
|
+
"\r\n",
|
329
|
+
file_descriptor,
|
330
|
+
file_encoding,
|
331
|
+
)
|
332
|
+
output_cabrillo_line(
|
333
|
+
f"CALLSIGN: {self.station.get('Call','')}",
|
334
|
+
"\r\n",
|
335
|
+
file_descriptor,
|
336
|
+
file_encoding,
|
337
|
+
)
|
338
|
+
output_cabrillo_line(
|
339
|
+
f"LOCATION: {self.station.get('ARRLSection', '')}",
|
340
|
+
"\r\n",
|
341
|
+
file_descriptor,
|
342
|
+
file_encoding,
|
343
|
+
)
|
344
|
+
output_cabrillo_line(
|
345
|
+
f"CATEGORY-OPERATOR: {self.contest_settings.get('OperatorCategory','')}",
|
346
|
+
"\r\n",
|
347
|
+
file_descriptor,
|
348
|
+
file_encoding,
|
349
|
+
)
|
350
|
+
output_cabrillo_line(
|
351
|
+
f"CATEGORY-ASSISTED: {self.contest_settings.get('AssistedCategory','')}",
|
352
|
+
"\r\n",
|
353
|
+
file_descriptor,
|
354
|
+
file_encoding,
|
355
|
+
)
|
356
|
+
output_cabrillo_line(
|
357
|
+
f"CATEGORY-BAND: {self.contest_settings.get('BandCategory','')}",
|
358
|
+
"\r\n",
|
359
|
+
file_descriptor,
|
360
|
+
file_encoding,
|
361
|
+
)
|
362
|
+
mode = self.contest_settings.get("ModeCategory", "")
|
363
|
+
if mode in ["SSB+CW", "SSB+CW+DIGITAL"]:
|
364
|
+
mode = "MIXED"
|
365
|
+
output_cabrillo_line(
|
366
|
+
f"CATEGORY-MODE: {mode}",
|
367
|
+
"\r\n",
|
368
|
+
file_descriptor,
|
369
|
+
file_encoding,
|
370
|
+
)
|
371
|
+
output_cabrillo_line(
|
372
|
+
f"CATEGORY-TRANSMITTER: {self.contest_settings.get('TransmitterCategory','')}",
|
373
|
+
"\r\n",
|
374
|
+
file_descriptor,
|
375
|
+
file_encoding,
|
376
|
+
)
|
377
|
+
if self.contest_settings.get("OverlayCategory", "") != "N/A":
|
378
|
+
output_cabrillo_line(
|
379
|
+
f"CATEGORY-OVERLAY: {self.contest_settings.get('OverlayCategory','')}",
|
380
|
+
"\r\n",
|
381
|
+
file_descriptor,
|
382
|
+
file_encoding,
|
383
|
+
)
|
384
|
+
output_cabrillo_line(
|
385
|
+
f"GRID-LOCATOR: {self.station.get('GridSquare','')}",
|
386
|
+
"\r\n",
|
387
|
+
file_descriptor,
|
388
|
+
file_encoding,
|
389
|
+
)
|
390
|
+
output_cabrillo_line(
|
391
|
+
f"CATEGORY-POWER: {self.contest_settings.get('PowerCategory','')}",
|
392
|
+
"\r\n",
|
393
|
+
file_descriptor,
|
394
|
+
file_encoding,
|
395
|
+
)
|
396
|
+
|
397
|
+
output_cabrillo_line(
|
398
|
+
f"CLAIMED-SCORE: {calc_score(self)}",
|
399
|
+
"\r\n",
|
400
|
+
file_descriptor,
|
401
|
+
file_encoding,
|
402
|
+
)
|
403
|
+
ops = f"@{self.station.get('Call','')}"
|
404
|
+
list_of_ops = self.database.get_ops()
|
405
|
+
for op in list_of_ops:
|
406
|
+
ops += f", {op.get('Operator', '')}"
|
407
|
+
output_cabrillo_line(
|
408
|
+
f"OPERATORS: {ops}",
|
409
|
+
"\r\n",
|
410
|
+
file_descriptor,
|
411
|
+
file_encoding,
|
412
|
+
)
|
413
|
+
output_cabrillo_line(
|
414
|
+
f"NAME: {self.station.get('Name', '')}",
|
415
|
+
"\r\n",
|
416
|
+
file_descriptor,
|
417
|
+
file_encoding,
|
418
|
+
)
|
419
|
+
output_cabrillo_line(
|
420
|
+
f"ADDRESS: {self.station.get('Street1', '')}",
|
421
|
+
"\r\n",
|
422
|
+
file_descriptor,
|
423
|
+
file_encoding,
|
424
|
+
)
|
425
|
+
output_cabrillo_line(
|
426
|
+
f"ADDRESS-CITY: {self.station.get('City', '')}",
|
427
|
+
"\r\n",
|
428
|
+
file_descriptor,
|
429
|
+
file_encoding,
|
430
|
+
)
|
431
|
+
output_cabrillo_line(
|
432
|
+
f"ADDRESS-STATE-PROVINCE: {self.station.get('State', '')}",
|
433
|
+
"\r\n",
|
434
|
+
file_descriptor,
|
435
|
+
file_encoding,
|
436
|
+
)
|
437
|
+
output_cabrillo_line(
|
438
|
+
f"ADDRESS-POSTALCODE: {self.station.get('Zip', '')}",
|
439
|
+
"\r\n",
|
440
|
+
file_descriptor,
|
441
|
+
file_encoding,
|
442
|
+
)
|
443
|
+
output_cabrillo_line(
|
444
|
+
f"ADDRESS-COUNTRY: {self.station.get('Country', '')}",
|
445
|
+
"\r\n",
|
446
|
+
file_descriptor,
|
447
|
+
file_encoding,
|
448
|
+
)
|
449
|
+
output_cabrillo_line(
|
450
|
+
f"EMAIL: {self.station.get('Email', '')}",
|
451
|
+
"\r\n",
|
452
|
+
file_descriptor,
|
453
|
+
file_encoding,
|
454
|
+
)
|
455
|
+
for contact in log:
|
456
|
+
the_date_and_time = contact.get("TS", "")
|
457
|
+
themode = contact.get("Mode", "")
|
458
|
+
if themode == "LSB" or themode == "USB":
|
459
|
+
themode = "PH"
|
460
|
+
frequency = str(int(contact.get("Freq", "0"))).rjust(5)
|
461
|
+
|
462
|
+
loggeddate = the_date_and_time[:10]
|
463
|
+
loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
|
464
|
+
output_cabrillo_line(
|
465
|
+
f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
|
466
|
+
f"{contact.get('StationPrefix', '').ljust(13)} "
|
467
|
+
f"{str(contact.get('SNT', '')).ljust(3)} "
|
468
|
+
f"{str(contact.get('SentNr', '')).ljust(6)} "
|
469
|
+
f"{contact.get('Call', '').ljust(13)} "
|
470
|
+
f"{str(contact.get('RCV', '')).ljust(3)} "
|
471
|
+
f"{str(contact.get('NR', '')).ljust(6)}",
|
472
|
+
"\r\n",
|
473
|
+
file_descriptor,
|
474
|
+
file_encoding,
|
475
|
+
)
|
476
|
+
output_cabrillo_line("END-OF-LOG:", "\r\n", file_descriptor, file_encoding)
|
477
|
+
self.show_message_box(f"Cabrillo saved to: {filename}")
|
478
|
+
except IOError as exception:
|
479
|
+
logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
|
480
|
+
self.show_message_box(f"Error saving Cabrillo: {exception} {filename}")
|
481
|
+
return
|
482
|
+
|
483
|
+
|
484
|
+
# def populate_history_info_line(self):
|
485
|
+
# result = self.database.fetch_call_history(self.callsign.text())
|
486
|
+
# if result:
|
487
|
+
# self.history_info.setText(
|
488
|
+
# f"{result.get('Call', '')}, {result.get('Exch1', '')}, {result.get('UserText','...')}"
|
489
|
+
# )
|
490
|
+
# else:
|
491
|
+
# self.history_info.setText("")
|
492
|
+
|
493
|
+
|
494
|
+
# def check_call_history(self):
|
495
|
+
# """"""
|
496
|
+
# result = self.database.fetch_call_history(self.callsign.text())
|
497
|
+
# print(f"{result=}")
|
498
|
+
# if result:
|
499
|
+
# self.history_info.setText(f"{result.get('UserText','')}")
|
500
|
+
# if self.other_2.text() == "":
|
501
|
+
# self.other_2.setText(f"{result.get('Exch1', '')}")
|
502
|
+
|
503
|
+
|
504
|
+
def process_esm(self, new_focused_widget=None, with_enter=False):
|
505
|
+
"""ESM State Machine"""
|
506
|
+
|
507
|
+
# self.pref["run_state"]
|
508
|
+
|
509
|
+
# -----===== Assigned F-Keys =====-----
|
510
|
+
# self.esm_dict["CQ"]
|
511
|
+
# self.esm_dict["EXCH"]
|
512
|
+
# self.esm_dict["QRZ"]
|
513
|
+
# self.esm_dict["AGN"]
|
514
|
+
# self.esm_dict["HISCALL"]
|
515
|
+
# self.esm_dict["MYCALL"]
|
516
|
+
# self.esm_dict["QSOB4"]
|
517
|
+
|
518
|
+
# ----==== text fields ====----
|
519
|
+
# self.callsign
|
520
|
+
# self.sent
|
521
|
+
# self.receive
|
522
|
+
# self.other_1
|
523
|
+
# self.other_2
|
524
|
+
|
525
|
+
if new_focused_widget is not None:
|
526
|
+
self.current_widget = self.inputs_dict.get(new_focused_widget)
|
527
|
+
|
528
|
+
# print(f"checking esm {self.current_widget=} {with_enter=} {self.pref.get("run_state")=}")
|
529
|
+
|
530
|
+
for a_button in [
|
531
|
+
self.esm_dict["CQ"],
|
532
|
+
self.esm_dict["EXCH"],
|
533
|
+
self.esm_dict["QRZ"],
|
534
|
+
self.esm_dict["AGN"],
|
535
|
+
self.esm_dict["HISCALL"],
|
536
|
+
self.esm_dict["MYCALL"],
|
537
|
+
self.esm_dict["QSOB4"],
|
538
|
+
]:
|
539
|
+
if a_button is not None:
|
540
|
+
self.restore_button_color(a_button)
|
541
|
+
|
542
|
+
buttons_to_send = []
|
543
|
+
|
544
|
+
if self.pref.get("run_state"):
|
545
|
+
if self.current_widget == "callsign":
|
546
|
+
if len(self.callsign.text()) < 3:
|
547
|
+
self.make_button_green(self.esm_dict["CQ"])
|
548
|
+
buttons_to_send.append(self.esm_dict["CQ"])
|
549
|
+
elif len(self.callsign.text()) > 2:
|
550
|
+
self.make_button_green(self.esm_dict["HISCALL"])
|
551
|
+
self.make_button_green(self.esm_dict["EXCH"])
|
552
|
+
buttons_to_send.append(self.esm_dict["HISCALL"])
|
553
|
+
buttons_to_send.append(self.esm_dict["EXCH"])
|
554
|
+
|
555
|
+
elif self.current_widget == "other_2":
|
556
|
+
if self.other_2.text() == "":
|
557
|
+
self.make_button_green(self.esm_dict["AGN"])
|
558
|
+
buttons_to_send.append(self.esm_dict["AGN"])
|
559
|
+
else:
|
560
|
+
self.make_button_green(self.esm_dict["QRZ"])
|
561
|
+
buttons_to_send.append(self.esm_dict["QRZ"])
|
562
|
+
buttons_to_send.append("LOGIT")
|
563
|
+
|
564
|
+
if with_enter is True and bool(len(buttons_to_send)):
|
565
|
+
for button in buttons_to_send:
|
566
|
+
if button:
|
567
|
+
if button == "LOGIT":
|
568
|
+
self.save_contact()
|
569
|
+
continue
|
570
|
+
self.process_function_key(button)
|
571
|
+
else:
|
572
|
+
if self.current_widget == "callsign":
|
573
|
+
if len(self.callsign.text()) > 2:
|
574
|
+
self.make_button_green(self.esm_dict["MYCALL"])
|
575
|
+
buttons_to_send.append(self.esm_dict["MYCALL"])
|
576
|
+
|
577
|
+
elif self.current_widget == "other_2":
|
578
|
+
if self.other_2.text() == "":
|
579
|
+
self.make_button_green(self.esm_dict["AGN"])
|
580
|
+
buttons_to_send.append(self.esm_dict["AGN"])
|
581
|
+
else:
|
582
|
+
self.make_button_green(self.esm_dict["EXCH"])
|
583
|
+
buttons_to_send.append(self.esm_dict["EXCH"])
|
584
|
+
buttons_to_send.append("LOGIT")
|
585
|
+
|
586
|
+
if with_enter is True and bool(len(buttons_to_send)):
|
587
|
+
for button in buttons_to_send:
|
588
|
+
if button:
|
589
|
+
if button == "LOGIT":
|
590
|
+
self.save_contact()
|
591
|
+
continue
|
592
|
+
self.process_function_key(button)
|
593
|
+
|
594
|
+
|
595
|
+
def get_mults(self):
|
596
|
+
"""Get mults for RTC XML"""
|
597
|
+
mults = {}
|
598
|
+
mults["country"], mults["state"] = show_mults(self, rtc=True)
|
599
|
+
return mults
|
600
|
+
|
601
|
+
|
602
|
+
def just_points(self):
|
603
|
+
"""Get points for RTC XML"""
|
604
|
+
return get_points(self)
|