not1mm 25.4.8__py3-none-any.whl → 25.4.11.3__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 +53 -18
- not1mm/data/greendot.png +0 -0
- not1mm/data/new_contest.ui +20 -0
- not1mm/lib/cwinterface.py +20 -2
- not1mm/lib/version.py +1 -1
- not1mm/plugins/ari_40_80.py +482 -0
- not1mm/plugins/cq_ww_cw.py +3 -1
- not1mm/plugins/sac_cw.py +668 -0
- not1mm/plugins/sac_ssb.py +668 -0
- not1mm/plugins/ukeidx.py +597 -0
- {not1mm-25.4.8.dist-info → not1mm-25.4.11.3.dist-info}/METADATA +24 -4
- {not1mm-25.4.8.dist-info → not1mm-25.4.11.3.dist-info}/RECORD +16 -12
- {not1mm-25.4.8.dist-info → not1mm-25.4.11.3.dist-info}/WHEEL +0 -0
- {not1mm-25.4.8.dist-info → not1mm-25.4.11.3.dist-info}/entry_points.txt +0 -0
- {not1mm-25.4.8.dist-info → not1mm-25.4.11.3.dist-info}/licenses/LICENSE +0 -0
- {not1mm-25.4.8.dist-info → not1mm-25.4.11.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,482 @@
|
|
1
|
+
"""CQ 160 CW plugin"""
|
2
|
+
|
3
|
+
# pylint: disable=invalid-name, c-extension-no-member, unused-import, line-too-long
|
4
|
+
|
5
|
+
import datetime
|
6
|
+
import logging
|
7
|
+
import platform
|
8
|
+
|
9
|
+
from pathlib import Path
|
10
|
+
|
11
|
+
from PyQt6 import QtWidgets
|
12
|
+
|
13
|
+
from not1mm.lib.plugin_common import gen_adif
|
14
|
+
from not1mm.lib.version import __version__
|
15
|
+
|
16
|
+
logger = logging.getLogger(__name__)
|
17
|
+
|
18
|
+
EXCHANGE_HINT = "Automobile Code"
|
19
|
+
|
20
|
+
name = "ARI 40 80"
|
21
|
+
cabrillo_name = "40-80"
|
22
|
+
mode = "BOTH" # CW SSB BOTH RTTY
|
23
|
+
|
24
|
+
columns = [
|
25
|
+
"YYYY-MM-DD HH:MM:SS",
|
26
|
+
"Call",
|
27
|
+
"Freq",
|
28
|
+
"Mode",
|
29
|
+
"Snt",
|
30
|
+
"Rcv",
|
31
|
+
"Exchange1",
|
32
|
+
"PTS",
|
33
|
+
]
|
34
|
+
|
35
|
+
advance_on_space = [True, True, True, True, True]
|
36
|
+
|
37
|
+
# 1 once per contest, 2 work each band, 3 each band/mode, 4 no dupe checking
|
38
|
+
dupe_type = 3
|
39
|
+
|
40
|
+
|
41
|
+
def init_contest(self):
|
42
|
+
"""setup plugin"""
|
43
|
+
set_tab_next(self)
|
44
|
+
set_tab_prev(self)
|
45
|
+
interface(self)
|
46
|
+
self.next_field = self.other_2
|
47
|
+
|
48
|
+
|
49
|
+
def interface(self):
|
50
|
+
"""Setup user interface"""
|
51
|
+
self.field1.show()
|
52
|
+
self.field2.show()
|
53
|
+
self.field3.hide()
|
54
|
+
self.field4.show()
|
55
|
+
self.snt_label.setText("SNT")
|
56
|
+
self.field1.setAccessibleName("RST Sent")
|
57
|
+
self.exch_label.setText("Automobile Code")
|
58
|
+
self.field4.setAccessibleName("Received Exchange")
|
59
|
+
|
60
|
+
|
61
|
+
def reset_label(self): # pylint: disable=unused-argument
|
62
|
+
"""reset label after field cleared"""
|
63
|
+
|
64
|
+
|
65
|
+
def set_tab_next(self):
|
66
|
+
"""Set TAB Advances"""
|
67
|
+
self.tab_next = {
|
68
|
+
self.callsign: self.sent,
|
69
|
+
self.sent: self.receive,
|
70
|
+
self.receive: self.other_2,
|
71
|
+
self.other_1: self.other_2,
|
72
|
+
self.other_2: self.callsign,
|
73
|
+
}
|
74
|
+
|
75
|
+
|
76
|
+
def set_tab_prev(self):
|
77
|
+
"""Set TAB Advances"""
|
78
|
+
self.tab_prev = {
|
79
|
+
self.callsign: self.other_2,
|
80
|
+
self.sent: self.callsign,
|
81
|
+
self.receive: self.sent,
|
82
|
+
self.other_1: self.receive,
|
83
|
+
self.other_2: self.receive,
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
def set_contact_vars(self):
|
88
|
+
"""Contest Specific"""
|
89
|
+
self.contact["SNT"] = self.sent.text()
|
90
|
+
self.contact["RCV"] = self.receive.text()
|
91
|
+
self.contact["SentNr"] = self.contest_settings.get("SentExchange", 0)
|
92
|
+
self.contact["Exchange1"] = self.other_2.text()
|
93
|
+
self.contact["IsMultiplier1"] = 0
|
94
|
+
|
95
|
+
|
96
|
+
def predupe(self): # pylint: disable=unused-argument
|
97
|
+
"""called after callsign entered"""
|
98
|
+
|
99
|
+
|
100
|
+
def prefill(self):
|
101
|
+
"""Fill SentNR"""
|
102
|
+
|
103
|
+
|
104
|
+
def points(self) -> int:
|
105
|
+
"""Calc point"""
|
106
|
+
|
107
|
+
# a . QSOs/HRDs in CW are worth 3 points;
|
108
|
+
# b. QSOs/HRDs in RTTY are worth 2 points;
|
109
|
+
# c. QSOs/HRDs in SSB are worth 1 point.
|
110
|
+
|
111
|
+
if self.contact_is_dupe > 0:
|
112
|
+
return 0
|
113
|
+
|
114
|
+
_mode = self.contact.get("Mode", "")
|
115
|
+
if _mode in "SSB, USB, LSB, FM, AM":
|
116
|
+
return 1
|
117
|
+
if _mode in "RTTY":
|
118
|
+
return 2
|
119
|
+
if _mode in "CW":
|
120
|
+
return 3
|
121
|
+
return 0
|
122
|
+
|
123
|
+
|
124
|
+
def show_mults(self):
|
125
|
+
"""Return display string for mults"""
|
126
|
+
query = f"select count(DISTINCT(Exchange1 || ':' || Mode || ':' || Band)) as mult_count from dxlog where ContestNR = {self.pref.get('contest', '1')};"
|
127
|
+
|
128
|
+
result = self.database.exec_sql(query)
|
129
|
+
if result:
|
130
|
+
return int(result.get("mult_count", 0))
|
131
|
+
return 0
|
132
|
+
|
133
|
+
|
134
|
+
def show_qso(self):
|
135
|
+
"""Return qso count"""
|
136
|
+
result = self.database.fetch_qso_count()
|
137
|
+
if result:
|
138
|
+
return int(result.get("qsos", 0))
|
139
|
+
return 0
|
140
|
+
|
141
|
+
|
142
|
+
def calc_score(self):
|
143
|
+
"""Return calculated score"""
|
144
|
+
result = self.database.fetch_points()
|
145
|
+
if result is not None:
|
146
|
+
score = result.get("Points", "0")
|
147
|
+
if score is None:
|
148
|
+
score = "0"
|
149
|
+
contest_points = int(score)
|
150
|
+
mults = int(show_mults(self))
|
151
|
+
return contest_points * mults
|
152
|
+
return 0
|
153
|
+
|
154
|
+
|
155
|
+
def adif(self):
|
156
|
+
"""Call the generate ADIF function"""
|
157
|
+
gen_adif(self, cabrillo_name, cabrillo_name)
|
158
|
+
|
159
|
+
|
160
|
+
def output_cabrillo_line(line_to_output, ending, file_descriptor, file_encoding):
|
161
|
+
""""""
|
162
|
+
print(
|
163
|
+
line_to_output.encode(file_encoding, errors="ignore").decode(),
|
164
|
+
end=ending,
|
165
|
+
file=file_descriptor,
|
166
|
+
)
|
167
|
+
|
168
|
+
|
169
|
+
def cabrillo(self, file_encoding):
|
170
|
+
"""Generates Cabrillo file. Maybe."""
|
171
|
+
# https://www.cw160.com/cabrillo.htm
|
172
|
+
logger.debug("******Cabrillo*****")
|
173
|
+
logger.debug("Station: %s", f"{self.station}")
|
174
|
+
logger.debug("Contest: %s", f"{self.contest_settings}")
|
175
|
+
now = datetime.datetime.now()
|
176
|
+
date_time = now.strftime("%Y-%m-%d_%H-%M-%S")
|
177
|
+
filename = (
|
178
|
+
str(Path.home())
|
179
|
+
+ "/"
|
180
|
+
+ f"{self.station.get('Call', '').upper()}_{cabrillo_name}_{date_time}.log"
|
181
|
+
)
|
182
|
+
logger.debug("%s", filename)
|
183
|
+
log = self.database.fetch_all_contacts_asc()
|
184
|
+
try:
|
185
|
+
with open(filename, "w", encoding=file_encoding, newline="") as file_descriptor:
|
186
|
+
output_cabrillo_line(
|
187
|
+
"START-OF-LOG: 3.0",
|
188
|
+
"\r\n",
|
189
|
+
file_descriptor,
|
190
|
+
file_encoding,
|
191
|
+
)
|
192
|
+
output_cabrillo_line(
|
193
|
+
f"CREATED-BY: Not1MM v{__version__}",
|
194
|
+
"\r\n",
|
195
|
+
file_descriptor,
|
196
|
+
file_encoding,
|
197
|
+
)
|
198
|
+
output_cabrillo_line(
|
199
|
+
f"CONTEST: {cabrillo_name}",
|
200
|
+
"\r\n",
|
201
|
+
file_descriptor,
|
202
|
+
file_encoding,
|
203
|
+
)
|
204
|
+
if self.station.get("Club", ""):
|
205
|
+
output_cabrillo_line(
|
206
|
+
f"CLUB: {self.station.get('Club', '').upper()}",
|
207
|
+
"\r\n",
|
208
|
+
file_descriptor,
|
209
|
+
file_encoding,
|
210
|
+
)
|
211
|
+
output_cabrillo_line(
|
212
|
+
f"CALLSIGN: {self.station.get('Call','')}",
|
213
|
+
"\r\n",
|
214
|
+
file_descriptor,
|
215
|
+
file_encoding,
|
216
|
+
)
|
217
|
+
output_cabrillo_line(
|
218
|
+
f"LOCATION: {self.station.get('ARRLSection', '')}",
|
219
|
+
"\r\n",
|
220
|
+
file_descriptor,
|
221
|
+
file_encoding,
|
222
|
+
)
|
223
|
+
output_cabrillo_line(
|
224
|
+
f"CATEGORY-OPERATOR: {self.contest_settings.get('OperatorCategory','')}",
|
225
|
+
"\r\n",
|
226
|
+
file_descriptor,
|
227
|
+
file_encoding,
|
228
|
+
)
|
229
|
+
output_cabrillo_line(
|
230
|
+
f"CATEGORY-ASSISTED: {self.contest_settings.get('AssistedCategory','')}",
|
231
|
+
"\r\n",
|
232
|
+
file_descriptor,
|
233
|
+
file_encoding,
|
234
|
+
)
|
235
|
+
output_cabrillo_line(
|
236
|
+
f"CATEGORY-BAND: {self.contest_settings.get('BandCategory','')}",
|
237
|
+
"\r\n",
|
238
|
+
file_descriptor,
|
239
|
+
file_encoding,
|
240
|
+
)
|
241
|
+
mode = self.contest_settings.get("ModeCategory", "")
|
242
|
+
if mode in ["SSB+CW", "SSB+CW+DIGITAL"]:
|
243
|
+
mode = "MIXED"
|
244
|
+
output_cabrillo_line(
|
245
|
+
f"CATEGORY-MODE: {mode}",
|
246
|
+
"\r\n",
|
247
|
+
file_descriptor,
|
248
|
+
file_encoding,
|
249
|
+
)
|
250
|
+
output_cabrillo_line(
|
251
|
+
f"CATEGORY-TRANSMITTER: {self.contest_settings.get('TransmitterCategory','')}",
|
252
|
+
"\r\n",
|
253
|
+
file_descriptor,
|
254
|
+
file_encoding,
|
255
|
+
)
|
256
|
+
if self.contest_settings.get("OverlayCategory", "") != "N/A":
|
257
|
+
output_cabrillo_line(
|
258
|
+
f"CATEGORY-OVERLAY: {self.contest_settings.get('OverlayCategory','')}",
|
259
|
+
"\r\n",
|
260
|
+
file_descriptor,
|
261
|
+
file_encoding,
|
262
|
+
)
|
263
|
+
output_cabrillo_line(
|
264
|
+
f"GRID-LOCATOR: {self.station.get('GridSquare','')}",
|
265
|
+
"\r\n",
|
266
|
+
file_descriptor,
|
267
|
+
file_encoding,
|
268
|
+
)
|
269
|
+
output_cabrillo_line(
|
270
|
+
f"CATEGORY-POWER: {self.contest_settings.get('PowerCategory','')}",
|
271
|
+
"\r\n",
|
272
|
+
file_descriptor,
|
273
|
+
file_encoding,
|
274
|
+
)
|
275
|
+
|
276
|
+
output_cabrillo_line(
|
277
|
+
f"CLAIMED-SCORE: {calc_score(self)}",
|
278
|
+
"\r\n",
|
279
|
+
file_descriptor,
|
280
|
+
file_encoding,
|
281
|
+
)
|
282
|
+
ops = f"@{self.station.get('Call','')}"
|
283
|
+
list_of_ops = self.database.get_ops()
|
284
|
+
for op in list_of_ops:
|
285
|
+
ops += f", {op.get('Operator', '')}"
|
286
|
+
output_cabrillo_line(
|
287
|
+
f"OPERATORS: {ops}",
|
288
|
+
"\r\n",
|
289
|
+
file_descriptor,
|
290
|
+
file_encoding,
|
291
|
+
)
|
292
|
+
output_cabrillo_line(
|
293
|
+
f"NAME: {self.station.get('Name', '')}",
|
294
|
+
"\r\n",
|
295
|
+
file_descriptor,
|
296
|
+
file_encoding,
|
297
|
+
)
|
298
|
+
output_cabrillo_line(
|
299
|
+
f"ADDRESS: {self.station.get('Street1', '')}",
|
300
|
+
"\r\n",
|
301
|
+
file_descriptor,
|
302
|
+
file_encoding,
|
303
|
+
)
|
304
|
+
output_cabrillo_line(
|
305
|
+
f"ADDRESS-CITY: {self.station.get('City', '')}",
|
306
|
+
"\r\n",
|
307
|
+
file_descriptor,
|
308
|
+
file_encoding,
|
309
|
+
)
|
310
|
+
output_cabrillo_line(
|
311
|
+
f"ADDRESS-STATE-PROVINCE: {self.station.get('State', '')}",
|
312
|
+
"\r\n",
|
313
|
+
file_descriptor,
|
314
|
+
file_encoding,
|
315
|
+
)
|
316
|
+
output_cabrillo_line(
|
317
|
+
f"ADDRESS-POSTALCODE: {self.station.get('Zip', '')}",
|
318
|
+
"\r\n",
|
319
|
+
file_descriptor,
|
320
|
+
file_encoding,
|
321
|
+
)
|
322
|
+
output_cabrillo_line(
|
323
|
+
f"ADDRESS-COUNTRY: {self.station.get('Country', '')}",
|
324
|
+
"\r\n",
|
325
|
+
file_descriptor,
|
326
|
+
file_encoding,
|
327
|
+
)
|
328
|
+
output_cabrillo_line(
|
329
|
+
f"EMAIL: {self.station.get('Email', '')}",
|
330
|
+
"\r\n",
|
331
|
+
file_descriptor,
|
332
|
+
file_encoding,
|
333
|
+
)
|
334
|
+
for contact in log:
|
335
|
+
the_date_and_time = contact.get("TS", "")
|
336
|
+
themode = contact.get("Mode", "")
|
337
|
+
if themode == "LSB" or themode == "USB":
|
338
|
+
themode = "PH"
|
339
|
+
if themode == "RTTY":
|
340
|
+
themode = "RY"
|
341
|
+
frequency = str(int(contact.get("Freq", "0"))).rjust(5)
|
342
|
+
|
343
|
+
loggeddate = the_date_and_time[:10]
|
344
|
+
loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
|
345
|
+
output_cabrillo_line(
|
346
|
+
f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
|
347
|
+
f"{contact.get('StationPrefix', '').ljust(13)} "
|
348
|
+
f"{str(contact.get('SNT', '')).ljust(3)} "
|
349
|
+
f"{str(contact.get('SentNr', '')).upper().ljust(6)} "
|
350
|
+
f"{contact.get('Call', '').ljust(13)} "
|
351
|
+
f"{str(contact.get('RCV', '')).ljust(3)} "
|
352
|
+
f"{str(contact.get('Exchange1', '')).upper().ljust(6)}",
|
353
|
+
"\r\n",
|
354
|
+
file_descriptor,
|
355
|
+
file_encoding,
|
356
|
+
)
|
357
|
+
output_cabrillo_line("END-OF-LOG:", "\r\n", file_descriptor, file_encoding)
|
358
|
+
self.show_message_box(f"Cabrillo saved to: {filename}")
|
359
|
+
except IOError as exception:
|
360
|
+
logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
|
361
|
+
self.show_message_box(f"Error saving Cabrillo: {exception} {filename}")
|
362
|
+
return
|
363
|
+
|
364
|
+
|
365
|
+
def trigger_update(self):
|
366
|
+
"""Triggers the log window to update."""
|
367
|
+
cmd = {}
|
368
|
+
cmd["cmd"] = "UPDATELOG"
|
369
|
+
if self.log_window:
|
370
|
+
self.log_window.msg_from_main(cmd)
|
371
|
+
|
372
|
+
|
373
|
+
def recalculate_mults(self):
|
374
|
+
"""Recalculates multipliers after change in logged qso."""
|
375
|
+
|
376
|
+
|
377
|
+
def process_esm(self, new_focused_widget=None, with_enter=False):
|
378
|
+
"""ESM State Machine"""
|
379
|
+
|
380
|
+
# self.pref["run_state"]
|
381
|
+
|
382
|
+
# -----===== Assigned F-Keys =====-----
|
383
|
+
# self.esm_dict["CQ"]
|
384
|
+
# self.esm_dict["EXCH"]
|
385
|
+
# self.esm_dict["QRZ"]
|
386
|
+
# self.esm_dict["AGN"]
|
387
|
+
# self.esm_dict["HISCALL"]
|
388
|
+
# self.esm_dict["MYCALL"]
|
389
|
+
# self.esm_dict["QSOB4"]
|
390
|
+
|
391
|
+
# ----==== text fields ====----
|
392
|
+
# self.callsign
|
393
|
+
# self.sent
|
394
|
+
# self.receive
|
395
|
+
# self.other_1
|
396
|
+
# self.other_2
|
397
|
+
|
398
|
+
if new_focused_widget is not None:
|
399
|
+
self.current_widget = self.inputs_dict.get(new_focused_widget)
|
400
|
+
|
401
|
+
# print(f"checking esm {self.current_widget=} {with_enter=} {self.pref.get("run_state")=}")
|
402
|
+
|
403
|
+
for a_button in [
|
404
|
+
self.esm_dict["CQ"],
|
405
|
+
self.esm_dict["EXCH"],
|
406
|
+
self.esm_dict["QRZ"],
|
407
|
+
self.esm_dict["AGN"],
|
408
|
+
self.esm_dict["HISCALL"],
|
409
|
+
self.esm_dict["MYCALL"],
|
410
|
+
self.esm_dict["QSOB4"],
|
411
|
+
]:
|
412
|
+
if a_button is not None:
|
413
|
+
self.restore_button_color(a_button)
|
414
|
+
|
415
|
+
buttons_to_send = []
|
416
|
+
|
417
|
+
if self.pref.get("run_state"):
|
418
|
+
if self.current_widget == "callsign":
|
419
|
+
if len(self.callsign.text()) < 3:
|
420
|
+
self.make_button_green(self.esm_dict["CQ"])
|
421
|
+
buttons_to_send.append(self.esm_dict["CQ"])
|
422
|
+
elif len(self.callsign.text()) > 2:
|
423
|
+
self.make_button_green(self.esm_dict["HISCALL"])
|
424
|
+
self.make_button_green(self.esm_dict["EXCH"])
|
425
|
+
buttons_to_send.append(self.esm_dict["HISCALL"])
|
426
|
+
buttons_to_send.append(self.esm_dict["EXCH"])
|
427
|
+
|
428
|
+
elif self.current_widget in ["other_2"]:
|
429
|
+
if self.other_2.text() == "":
|
430
|
+
self.make_button_green(self.esm_dict["AGN"])
|
431
|
+
buttons_to_send.append(self.esm_dict["AGN"])
|
432
|
+
else:
|
433
|
+
self.make_button_green(self.esm_dict["QRZ"])
|
434
|
+
buttons_to_send.append(self.esm_dict["QRZ"])
|
435
|
+
buttons_to_send.append("LOGIT")
|
436
|
+
|
437
|
+
if with_enter is True and bool(len(buttons_to_send)):
|
438
|
+
for button in buttons_to_send:
|
439
|
+
if button:
|
440
|
+
if button == "LOGIT":
|
441
|
+
self.save_contact()
|
442
|
+
continue
|
443
|
+
self.process_function_key(button)
|
444
|
+
else:
|
445
|
+
if self.current_widget == "callsign":
|
446
|
+
if len(self.callsign.text()) > 2:
|
447
|
+
self.make_button_green(self.esm_dict["MYCALL"])
|
448
|
+
buttons_to_send.append(self.esm_dict["MYCALL"])
|
449
|
+
|
450
|
+
elif self.current_widget in ["other_2"]:
|
451
|
+
if self.other_2.text() == "":
|
452
|
+
self.make_button_green(self.esm_dict["AGN"])
|
453
|
+
buttons_to_send.append(self.esm_dict["AGN"])
|
454
|
+
else:
|
455
|
+
self.make_button_green(self.esm_dict["EXCH"])
|
456
|
+
buttons_to_send.append(self.esm_dict["EXCH"])
|
457
|
+
buttons_to_send.append("LOGIT")
|
458
|
+
|
459
|
+
if with_enter is True and bool(len(buttons_to_send)):
|
460
|
+
for button in buttons_to_send:
|
461
|
+
if button:
|
462
|
+
if button == "LOGIT":
|
463
|
+
self.save_contact()
|
464
|
+
continue
|
465
|
+
self.process_function_key(button)
|
466
|
+
|
467
|
+
|
468
|
+
def populate_history_info_line(self):
|
469
|
+
result = self.database.fetch_call_history(self.callsign.text())
|
470
|
+
if result:
|
471
|
+
self.history_info.setText(f"{result.get('Call', '')}, {result.get('Sect', '')}")
|
472
|
+
else:
|
473
|
+
self.history_info.setText("")
|
474
|
+
|
475
|
+
|
476
|
+
def check_call_history(self):
|
477
|
+
""""""
|
478
|
+
result = self.database.fetch_call_history(self.callsign.text())
|
479
|
+
if result:
|
480
|
+
self.history_info.setText(f"{result.get('UserText','')}")
|
481
|
+
if self.other_2.text() == "":
|
482
|
+
self.other_2.setText(f"{result.get('Sect', '')}")
|
not1mm/plugins/cq_ww_cw.py
CHANGED
@@ -38,7 +38,7 @@
|
|
38
38
|
|
39
39
|
import datetime
|
40
40
|
import logging
|
41
|
-
|
41
|
+
import time
|
42
42
|
from pathlib import Path
|
43
43
|
|
44
44
|
from PyQt6 import QtWidgets
|
@@ -496,6 +496,7 @@ def process_esm(self, new_focused_widget=None, with_enter=False):
|
|
496
496
|
self.save_contact()
|
497
497
|
continue
|
498
498
|
self.process_function_key(button)
|
499
|
+
time.sleep(0.2)
|
499
500
|
else:
|
500
501
|
if self.current_widget == "callsign":
|
501
502
|
if len(self.callsign.text()) > 2:
|
@@ -521,6 +522,7 @@ def process_esm(self, new_focused_widget=None, with_enter=False):
|
|
521
522
|
self.save_contact()
|
522
523
|
continue
|
523
524
|
self.process_function_key(button)
|
525
|
+
time.sleep(0.2)
|
524
526
|
|
525
527
|
|
526
528
|
def populate_history_info_line(self):
|