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