not1mm 25.4.7__py3-none-any.whl → 25.4.9__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 CHANGED
@@ -795,12 +795,20 @@ class MainWindow(QtWidgets.QMainWindow):
795
795
  try:
796
796
  with open(filename, "rt", encoding="utf-8") as file_descriptor:
797
797
  lines = file_descriptor.readlines()
798
- if "!!Order!!" in lines[0]:
799
- item_names = lines[0].strip().split(",")
798
+ substring_to_find = "!!Order!!"
799
+ found_index = -1 # Initialize to -1 to indicate not found
800
+
801
+ for index, item in enumerate(lines):
802
+ if substring_to_find in item:
803
+ found_index = index
804
+ break # Exit the loop once found
805
+
806
+ if found_index != -1:
807
+ item_names = lines[found_index].strip().split(",")
800
808
  # ['!!Order!!', 'Call', 'Sect', 'State', 'CK', 'UserText', '']
801
809
  item_names = item_names[1:]
802
810
  # ['Call', 'Sect', 'State', 'CK', 'UserText', '']
803
- lines = lines[1:]
811
+ lines = lines[found_index + 1 :]
804
812
  group_list = []
805
813
  for line in lines:
806
814
  if line.startswith("#"):
@@ -1026,7 +1034,6 @@ class MainWindow(QtWidgets.QMainWindow):
1026
1034
  if self.bandmap_window:
1027
1035
  self.bandmap_window.msg_from_main(cmd)
1028
1036
 
1029
-
1030
1037
  if setdarkmode:
1031
1038
  darkPalette = QPalette()
1032
1039
  darkColor = QColor(56, 56, 56)
@@ -442,6 +442,11 @@
442
442
  <string>STEW PERRY TOPBAND</string>
443
443
  </property>
444
444
  </item>
445
+ <item>
446
+ <property name="text">
447
+ <string>UKEIDX</string>
448
+ </property>
449
+ </item>
445
450
  <item>
446
451
  <property name="text">
447
452
  <string>WEEKLY RTTY</string>
not1mm/lib/version.py CHANGED
@@ -1,3 +1,4 @@
1
1
  """It's the version"""
2
2
 
3
- __version__ = "25.4.7"
3
+ __version__ = "25.4.9"
4
+
@@ -0,0 +1,597 @@
1
+ """10 10 fall cw plugin"""
2
+
3
+ # pylint: disable=invalid-name, unused-argument, unused-variable, c-extension-no-member, unused-import
4
+
5
+ import datetime
6
+ import logging
7
+ from pathlib import Path
8
+
9
+ from PyQt6 import QtWidgets
10
+
11
+ from not1mm.lib.plugin_common import gen_adif, get_points, online_score_xml
12
+ from not1mm.lib.version import __version__
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ EXCHANGE_HINT = "# or # And Dist"
17
+
18
+ ukei_pfx = [
19
+ "G",
20
+ "GD",
21
+ "GJ",
22
+ "GM",
23
+ "GI",
24
+ "GW",
25
+ "GU",
26
+ "EI",
27
+ ]
28
+
29
+ name = "UKEI-DX"
30
+ cabrillo_name = "UKEI-DX"
31
+ mode = "BOTH" # CW SSB BOTH RTTY
32
+ # columns = [0, 1, 2, 3, 4, 5, 6, 15]
33
+ columns = [
34
+ "YYYY-MM-DD HH:MM:SS",
35
+ "Call",
36
+ "Freq",
37
+ "Snt",
38
+ "Rcv",
39
+ "SentNr",
40
+ "RcvNr",
41
+ "PTS",
42
+ ]
43
+
44
+ # 1 once per contest, 2 work each band, 3 each band/mode, 4 no dupe checking
45
+ dupe_type = 2
46
+
47
+
48
+ def init_contest(self):
49
+ """setup plugin"""
50
+ set_tab_next(self)
51
+ set_tab_prev(self)
52
+ interface(self)
53
+ self.next_field = self.other_2
54
+
55
+
56
+ def interface(self):
57
+ """Setup user interface"""
58
+ self.field1.show()
59
+ self.field2.show()
60
+ self.field3.show()
61
+ self.field4.show()
62
+ self.snt_label.setText("SNT")
63
+ self.field1.setAccessibleName("RST Sent")
64
+ self.other_label.setText("Sent Nr")
65
+ self.field2.setAccessibleName("Sent Number")
66
+ self.exch_label.setText("# and Dist")
67
+ self.field4.setAccessibleName("Number and District")
68
+
69
+
70
+ def reset_label(self):
71
+ """reset label after field cleared"""
72
+
73
+
74
+ def set_tab_next(self):
75
+ """Set TAB Advances"""
76
+ self.tab_next = {
77
+ self.callsign: self.sent,
78
+ self.sent: self.receive,
79
+ self.receive: self.other_1,
80
+ self.other_1: self.other_2,
81
+ self.other_2: self.callsign,
82
+ }
83
+
84
+
85
+ def set_tab_prev(self):
86
+ """Set TAB Advances"""
87
+ self.tab_prev = {
88
+ self.callsign: self.other_2,
89
+ self.sent: self.callsign,
90
+ self.receive: self.sent,
91
+ self.other_1: self.receive,
92
+ self.other_2: self.other_1,
93
+ }
94
+
95
+
96
+ def validate(self):
97
+ """doc"""
98
+ return True
99
+
100
+
101
+ def set_contact_vars(self):
102
+ """Contest Specific"""
103
+ self.contact["SNT"] = self.sent.text()
104
+ self.contact["RCV"] = self.receive.text()
105
+ self.contact["NR"] = self.other_2.text().upper()
106
+ self.contact["SentNr"] = self.other_1.text()
107
+
108
+
109
+ def predupe(self):
110
+ """called after callsign entered"""
111
+
112
+
113
+ def prefill(self):
114
+ """Fill sentnr"""
115
+ exch = str(self.contest_settings.get("SentExchange", 0))
116
+ result = self.database.get_serial()
117
+ serial_nr = str(result.get("serial_nr", "1")).zfill(3)
118
+ if serial_nr == "None":
119
+ serial_nr = "001"
120
+ if len(self.other_1.text()) == 0:
121
+ self.other_1.setText(exch.replace("#", serial_nr))
122
+
123
+
124
+ def points(self):
125
+ """Calc point"""
126
+
127
+ # UK/EI stations contacting :
128
+ # UK/EI/Europe 80m, 40m - 4 points 20m, 15m, 10m - 2 points
129
+ # DX (Outside Europe) 80m, 40m - 8 points 20m, 15m, 10m - 4 points
130
+
131
+ # Note : For UK/EI stations only, all QSOs will score double points between the hours of 0100z and 0459z.
132
+
133
+ # European stations contacting :
134
+ # UK/EI 80m, 40m - 4 points 20m, 15m, 10m - 2 points
135
+ # Europe 80m, 40m - 2 points 20m, 15m, 10m - 1 points
136
+ # DX (Outside Europe) 80m, 40m - 4 points 20m, 15m, 10m - 2 points
137
+
138
+ # DX (Outside Europe) contacting :
139
+ # UK/EI 80m, 40m - 8 points 20m, 15m, 10m - 4 points
140
+ # Europe 80m, 40m - 4 points 20m, 15m, 10m - 2 points
141
+ # DX (Outside Europe) 80m, 40m - 2 points 20m, 15m, 10m - 1 points
142
+
143
+ # f"{primary_pfx}: {continent}/{entity} cq:{cq} itu:{itu}"
144
+
145
+ if self.contact_is_dupe > 0:
146
+ return 0
147
+
148
+ myprimary_pfx = ""
149
+ # mycountry = ""
150
+ mycontinent = ""
151
+ hisprimary_pfx = ""
152
+ # hiscountry = ""
153
+ hiscontinent = ""
154
+
155
+ result = self.cty_lookup(self.station.get("Call", ""))
156
+ if result:
157
+ for item in result.items():
158
+ myprimary_pfx = item[1].get("primary_pfx", "")
159
+ # mycountry = item[1].get("entity", "")
160
+ mycontinent = item[1].get("continent", "")
161
+
162
+ result = self.cty_lookup(self.contact.get("Call", ""))
163
+ if result:
164
+ for item in result.items():
165
+ hisprimary_pfx = item[1].get("primary_pfx", "")
166
+ # hiscountry = item[1].get("entity", "")
167
+ hiscontinent = item[1].get("continent", "")
168
+
169
+ st = 100
170
+ et = 459
171
+ zt = datetime.datetime.now(datetime.timezone.utc).isoformat(" ")[11:16]
172
+ ct = int(zt[0:2]) * 100 + int(zt[3:5])
173
+ double_window = st <= ct <= et
174
+
175
+ # UK/EI stations:
176
+ if myprimary_pfx in ukei_pfx:
177
+ if hiscontinent == "EU":
178
+ if self.contact.get("Band", 0) in ["3.5", "7"]:
179
+ return 4 + (4 * double_window)
180
+ return 2 + (2 * double_window)
181
+ if self.contact.get("Band", 0) in ["3.5", "7"]:
182
+ return 8 + (8 * double_window)
183
+ return 4 + (4 * double_window)
184
+
185
+ # European stations:
186
+ if mycontinent == "EU":
187
+ if hisprimary_pfx in ukei_pfx:
188
+ if self.contact.get("Band", 0) in ["3.5", "7"]:
189
+ return 4
190
+ return 2
191
+ elif hiscontinent == "EU":
192
+ if self.contact.get("Band", 0) in ["3.5", "7"]:
193
+ return 2
194
+ return 1
195
+ if self.contact.get("Band", 0) in ["3.5", "7"]:
196
+ return 4
197
+ return 2
198
+
199
+ # DX (Outside Europe)
200
+ if mycontinent != "EU":
201
+ if hisprimary_pfx in ukei_pfx:
202
+ if self.contact.get("Band", "") in ["3.5", "7"]:
203
+ return 8
204
+ return 4
205
+ elif hiscontinent == "EU":
206
+ if self.contact.get("Band", "") in ["3.5", "7"]:
207
+ return 4
208
+ return 2
209
+ if self.contact.get("Band", "") in ["3.5", "7"]:
210
+ return 2
211
+ return 1
212
+
213
+ return 0
214
+
215
+
216
+ def show_mults(self):
217
+ """Return display string for mults"""
218
+
219
+ query = f"SELECT COUNT(DISTINCT CountryPrefix) as dxcc_count FROM DXLOG WHERE CountryPrefix NOT IN ('EI', 'G', 'GD', 'GI', 'GJ', 'GM', 'GU', 'GW') and ContestNR = {self.pref.get('contest', '1')};"
220
+ result = self.database.exec_sql(query)
221
+ dxcc_count = result.get("dxcc_count", 0)
222
+
223
+ query = f"SELECT COUNT(DISTINCT SUBSTR(NR, LENGTH(NR) - 1)) as code_count FROM DXLOG WHERE ContestNR = {self.pref.get('contest', '1')} and typeof(NR) = 'text';"
224
+ result = self.database.exec_sql(query)
225
+ code_count = result.get("code_count", 0)
226
+
227
+ return dxcc_count + code_count
228
+
229
+
230
+ def show_qso(self):
231
+ """Return qso count"""
232
+ result = self.database.fetch_qso_count()
233
+ if result:
234
+ return int(result.get("qsos", 0))
235
+ return 0
236
+
237
+
238
+ def calc_score(self):
239
+ """Return calculated score"""
240
+ result = self.database.fetch_points()
241
+ if result is not None:
242
+ score = result.get("Points", "0")
243
+ if score is None:
244
+ score = "0"
245
+ contest_points = int(score)
246
+ mults = show_mults(self)
247
+ return contest_points * mults
248
+ return 0
249
+
250
+
251
+ def adif(self):
252
+ """Call the generate ADIF function"""
253
+ gen_adif(self, cabrillo_name)
254
+
255
+
256
+ def output_cabrillo_line(line_to_output, ending, file_descriptor, file_encoding):
257
+ """"""
258
+ print(
259
+ line_to_output.encode(file_encoding, errors="ignore").decode(),
260
+ end=ending,
261
+ file=file_descriptor,
262
+ )
263
+
264
+
265
+ def cabrillo(self, file_encoding):
266
+ """Generates Cabrillo file. Maybe."""
267
+ # https://www.cqwpx.com/cabrillo.htm
268
+ logger.debug("******Cabrillo*****")
269
+ logger.debug("Station: %s", f"{self.station}")
270
+ logger.debug("Contest: %s", f"{self.contest_settings}")
271
+ now = datetime.datetime.now()
272
+ date_time = now.strftime("%Y-%m-%d_%H-%M-%S")
273
+ filename = (
274
+ str(Path.home())
275
+ + "/"
276
+ + f"{self.station.get('Call', '').upper()}_{cabrillo_name}_{date_time}.log"
277
+ )
278
+ logger.debug("%s", filename)
279
+ log = self.database.fetch_all_contacts_asc()
280
+ try:
281
+ with open(filename, "w", encoding=file_encoding, newline="") as file_descriptor:
282
+ output_cabrillo_line(
283
+ "START-OF-LOG: 3.0",
284
+ "\r\n",
285
+ file_descriptor,
286
+ file_encoding,
287
+ )
288
+ output_cabrillo_line(
289
+ f"CREATED-BY: Not1MM v{__version__}",
290
+ "\r\n",
291
+ file_descriptor,
292
+ file_encoding,
293
+ )
294
+ output_cabrillo_line(
295
+ f"CONTEST: {cabrillo_name}",
296
+ "\r\n",
297
+ file_descriptor,
298
+ file_encoding,
299
+ )
300
+ if self.station.get("Club", ""):
301
+ output_cabrillo_line(
302
+ f"CLUB: {self.station.get('Club', '').upper()}",
303
+ "\r\n",
304
+ file_descriptor,
305
+ file_encoding,
306
+ )
307
+ output_cabrillo_line(
308
+ f"CALLSIGN: {self.station.get('Call','')}",
309
+ "\r\n",
310
+ file_descriptor,
311
+ file_encoding,
312
+ )
313
+ output_cabrillo_line(
314
+ f"LOCATION: {self.station.get('ARRLSection', '')}",
315
+ "\r\n",
316
+ file_descriptor,
317
+ file_encoding,
318
+ )
319
+ output_cabrillo_line(
320
+ f"CATEGORY-OPERATOR: {self.contest_settings.get('OperatorCategory','')}",
321
+ "\r\n",
322
+ file_descriptor,
323
+ file_encoding,
324
+ )
325
+ output_cabrillo_line(
326
+ f"CATEGORY-ASSISTED: {self.contest_settings.get('AssistedCategory','')}",
327
+ "\r\n",
328
+ file_descriptor,
329
+ file_encoding,
330
+ )
331
+ output_cabrillo_line(
332
+ f"CATEGORY-BAND: {self.contest_settings.get('BandCategory','')}",
333
+ "\r\n",
334
+ file_descriptor,
335
+ file_encoding,
336
+ )
337
+ mode = self.contest_settings.get("ModeCategory", "")
338
+ if mode in ["SSB+CW", "SSB+CW+DIGITAL"]:
339
+ mode = "MIXED"
340
+ output_cabrillo_line(
341
+ f"CATEGORY-MODE: {mode}",
342
+ "\r\n",
343
+ file_descriptor,
344
+ file_encoding,
345
+ )
346
+ output_cabrillo_line(
347
+ f"CATEGORY-TRANSMITTER: {self.contest_settings.get('TransmitterCategory','')}",
348
+ "\r\n",
349
+ file_descriptor,
350
+ file_encoding,
351
+ )
352
+ if self.contest_settings.get("OverlayCategory", "") != "N/A":
353
+ output_cabrillo_line(
354
+ f"CATEGORY-OVERLAY: {self.contest_settings.get('OverlayCategory','')}",
355
+ "\r\n",
356
+ file_descriptor,
357
+ file_encoding,
358
+ )
359
+ output_cabrillo_line(
360
+ f"GRID-LOCATOR: {self.station.get('GridSquare','')}",
361
+ "\r\n",
362
+ file_descriptor,
363
+ file_encoding,
364
+ )
365
+ output_cabrillo_line(
366
+ f"CATEGORY-POWER: {self.contest_settings.get('PowerCategory','')}",
367
+ "\r\n",
368
+ file_descriptor,
369
+ file_encoding,
370
+ )
371
+
372
+ output_cabrillo_line(
373
+ f"CLAIMED-SCORE: {calc_score(self)}",
374
+ "\r\n",
375
+ file_descriptor,
376
+ file_encoding,
377
+ )
378
+ ops = f"@{self.station.get('Call','')}"
379
+ list_of_ops = self.database.get_ops()
380
+ for op in list_of_ops:
381
+ ops += f", {op.get('Operator', '')}"
382
+ output_cabrillo_line(
383
+ f"OPERATORS: {ops}",
384
+ "\r\n",
385
+ file_descriptor,
386
+ file_encoding,
387
+ )
388
+ output_cabrillo_line(
389
+ f"NAME: {self.station.get('Name', '')}",
390
+ "\r\n",
391
+ file_descriptor,
392
+ file_encoding,
393
+ )
394
+ output_cabrillo_line(
395
+ f"ADDRESS: {self.station.get('Street1', '')}",
396
+ "\r\n",
397
+ file_descriptor,
398
+ file_encoding,
399
+ )
400
+ output_cabrillo_line(
401
+ f"ADDRESS-CITY: {self.station.get('City', '')}",
402
+ "\r\n",
403
+ file_descriptor,
404
+ file_encoding,
405
+ )
406
+ output_cabrillo_line(
407
+ f"ADDRESS-STATE-PROVINCE: {self.station.get('State', '')}",
408
+ "\r\n",
409
+ file_descriptor,
410
+ file_encoding,
411
+ )
412
+ output_cabrillo_line(
413
+ f"ADDRESS-POSTALCODE: {self.station.get('Zip', '')}",
414
+ "\r\n",
415
+ file_descriptor,
416
+ file_encoding,
417
+ )
418
+ output_cabrillo_line(
419
+ f"ADDRESS-COUNTRY: {self.station.get('Country', '')}",
420
+ "\r\n",
421
+ file_descriptor,
422
+ file_encoding,
423
+ )
424
+ output_cabrillo_line(
425
+ f"EMAIL: {self.station.get('Email', '')}",
426
+ "\r\n",
427
+ file_descriptor,
428
+ file_encoding,
429
+ )
430
+ for contact in log:
431
+ the_date_and_time = contact.get("TS", "")
432
+ themode = contact.get("Mode", "")
433
+ if themode == "LSB" or themode == "USB":
434
+ themode = "PH"
435
+ frequency = str(int(contact.get("Freq", "0"))).rjust(5)
436
+
437
+ loggeddate = the_date_and_time[:10]
438
+ loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
439
+ sentnr = str(contact.get("SentNr", "")).upper().split()
440
+ if len(sentnr) == 2:
441
+ sentnr = sentnr[0].zfill(3) + " " + sentnr[1]
442
+ else:
443
+ sentnr = sentnr[0].zfill(3) + " --"
444
+
445
+ nr = str(contact.get("NR", "")).upper().split()
446
+ if len(nr) == 2:
447
+ nr = nr[0].zfill(3) + " " + nr[1]
448
+ else:
449
+ if nr[0][-2:].isalpha():
450
+ nr = nr[0][:-2].zfill(3) + " " + nr[0][-2:]
451
+ else:
452
+ nr = nr[0].zfill(3) + " --"
453
+
454
+ output_cabrillo_line(
455
+ f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
456
+ f"{contact.get('StationPrefix', '').ljust(13)} "
457
+ f"{str(contact.get('SNT', '')).ljust(3)} "
458
+ f"{sentnr} "
459
+ f"{contact.get('Call', '').ljust(13)} "
460
+ f"{str(contact.get('RCV', '')).ljust(3)} "
461
+ f"{nr}",
462
+ "\r\n",
463
+ file_descriptor,
464
+ file_encoding,
465
+ )
466
+ output_cabrillo_line("END-OF-LOG:", "\r\n", file_descriptor, file_encoding)
467
+ self.show_message_box(f"Cabrillo saved to: {filename}")
468
+ except IOError as exception:
469
+ logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
470
+ self.show_message_box(f"Error saving Cabrillo: {exception} {filename}")
471
+ return
472
+
473
+
474
+ def recalculate_mults(self):
475
+ """Recalculates multipliers after change in logged qso."""
476
+
477
+
478
+ def process_esm(self, new_focused_widget=None, with_enter=False):
479
+ """ESM State Machine"""
480
+
481
+ # self.pref["run_state"]
482
+
483
+ # -----===== Assigned F-Keys =====-----
484
+ # self.esm_dict["CQ"]
485
+ # self.esm_dict["EXCH"]
486
+ # self.esm_dict["QRZ"]
487
+ # self.esm_dict["AGN"]
488
+ # self.esm_dict["HISCALL"]
489
+ # self.esm_dict["MYCALL"]
490
+ # self.esm_dict["QSOB4"]
491
+
492
+ # ----==== text fields ====----
493
+ # self.callsign
494
+ # self.sent
495
+ # self.receive
496
+ # self.other_1
497
+ # self.other_2
498
+
499
+ if new_focused_widget is not None:
500
+ self.current_widget = self.inputs_dict.get(new_focused_widget)
501
+
502
+ # print(f"checking esm {self.current_widget=} {with_enter=} {self.pref.get("run_state")=}")
503
+
504
+ for a_button in [
505
+ self.esm_dict["CQ"],
506
+ self.esm_dict["EXCH"],
507
+ self.esm_dict["QRZ"],
508
+ self.esm_dict["AGN"],
509
+ self.esm_dict["HISCALL"],
510
+ self.esm_dict["MYCALL"],
511
+ self.esm_dict["QSOB4"],
512
+ ]:
513
+ if a_button is not None:
514
+ self.restore_button_color(a_button)
515
+
516
+ buttons_to_send = []
517
+
518
+ if self.pref.get("run_state"):
519
+ if self.current_widget == "callsign":
520
+ if len(self.callsign.text()) < 3:
521
+ self.make_button_green(self.esm_dict["CQ"])
522
+ buttons_to_send.append(self.esm_dict["CQ"])
523
+ elif len(self.callsign.text()) > 2:
524
+ self.make_button_green(self.esm_dict["HISCALL"])
525
+ self.make_button_green(self.esm_dict["EXCH"])
526
+ buttons_to_send.append(self.esm_dict["HISCALL"])
527
+ buttons_to_send.append(self.esm_dict["EXCH"])
528
+
529
+ elif self.current_widget in ["other_2"]:
530
+ if self.other_2.text() == "":
531
+ self.make_button_green(self.esm_dict["AGN"])
532
+ buttons_to_send.append(self.esm_dict["AGN"])
533
+ else:
534
+ self.make_button_green(self.esm_dict["QRZ"])
535
+ buttons_to_send.append(self.esm_dict["QRZ"])
536
+ buttons_to_send.append("LOGIT")
537
+
538
+ if with_enter is True and bool(len(buttons_to_send)):
539
+ for button in buttons_to_send:
540
+ if button:
541
+ if button == "LOGIT":
542
+ self.save_contact()
543
+ continue
544
+ self.process_function_key(button)
545
+ else:
546
+ if self.current_widget == "callsign":
547
+ if len(self.callsign.text()) > 2:
548
+ self.make_button_green(self.esm_dict["MYCALL"])
549
+ buttons_to_send.append(self.esm_dict["MYCALL"])
550
+
551
+ elif self.current_widget in ["other_2"]:
552
+ if self.other_2.text() == "":
553
+ self.make_button_green(self.esm_dict["AGN"])
554
+ buttons_to_send.append(self.esm_dict["AGN"])
555
+ else:
556
+ self.make_button_green(self.esm_dict["EXCH"])
557
+ buttons_to_send.append(self.esm_dict["EXCH"])
558
+ buttons_to_send.append("LOGIT")
559
+
560
+ if with_enter is True and bool(len(buttons_to_send)):
561
+ for button in buttons_to_send:
562
+ if button:
563
+ if button == "LOGIT":
564
+ self.save_contact()
565
+ continue
566
+ self.process_function_key(button)
567
+
568
+
569
+ def get_mults(self):
570
+ """"""
571
+
572
+ mults = {}
573
+ return mults
574
+
575
+
576
+ def just_points(self):
577
+ """"""
578
+ return get_points(self)
579
+
580
+
581
+ def populate_history_info_line(self):
582
+ result = self.database.fetch_call_history(self.callsign.text())
583
+ if result:
584
+ self.history_info.setText(
585
+ f"{result.get('Call', '')}, {result.get('Exch1', '')}, {result.get('UserText','...')}"
586
+ )
587
+ else:
588
+ self.history_info.setText("")
589
+
590
+
591
+ def check_call_history(self):
592
+ """"""
593
+ result = self.database.fetch_call_history(self.callsign.text())
594
+ if result:
595
+ self.history_info.setText(f"{result.get('UserText','')}")
596
+ if self.other_2.text() == "":
597
+ self.other_2.setText(f"{result.get('Exch1', '')}")
not1mm/statistics.py CHANGED
@@ -6,7 +6,7 @@ import os
6
6
 
7
7
  from PyQt6 import uic, QtWidgets
8
8
  from PyQt6.QtWidgets import QDockWidget
9
- from PyQt6.QtCore import pyqtSignal
9
+ from PyQt6.QtCore import pyqtSignal, Qt
10
10
 
11
11
  import not1mm.fsutils as fsutils
12
12
  from not1mm.lib.database import DataBase
@@ -98,6 +98,7 @@ class StatsWindow(QDockWidget):
98
98
  if self.active is False:
99
99
  return
100
100
  self.tableWidget.clear()
101
+ self.tableWidget.setFocusPolicy(Qt.FocusPolicy.NoFocus)
101
102
  self.tableWidget.setColumnCount(7)
102
103
  self.tableWidget.setHorizontalHeaderLabels(
103
104
  ["BAND", "QSO", "CALLS", "CW", "PH", "DI", "PTS"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: not1mm
3
- Version: 25.4.7
3
+ Version: 25.4.9
4
4
  Summary: NOT1MM Logger
5
5
  Author-email: Michael Bridak <michael.bridak@gmail.com>
6
6
  License: GPL-3.0-or-later
@@ -141,6 +141,7 @@ Dynamic: license-file
141
141
  - [The exchange](#the-exchange)
142
142
  - [RAEM](#raem)
143
143
  - [RandomGram](#randomgram)
144
+ - [UKEI DX](#ukei-dx)
144
145
 
145
146
  ## What and Why is Not1MM
146
147
 
@@ -243,11 +244,14 @@ generated, 'cause I'm lazy, list of those who've submitted PR's.
243
244
  - REF CW, SSB
244
245
  - SPDX
245
246
  - Stew Perry Topband
247
+ - UK/EI DX
246
248
  - Weekly RTTY
247
249
  - Winter Field Day
248
250
 
249
251
  ## Recent Changes
250
252
 
253
+ - [25-4-9] Added UKEI DX
254
+ - [25-4-8] Remove focus from statistics table widget.
251
255
  - [25-4-7] Merge in changes from dj1yfk correcting SPDX Cabrillo name.
252
256
  - [25-4-5] Add SPDX.
253
257
  - [25-4-2] Add some tool tips to bandmap and main. Updated Zoom buttons on bandmap. Updated minimum Python version to 3.10.
@@ -1033,3 +1037,8 @@ for me 33N117W. And in the exchange macro put `# {EXCH}`.
1033
1037
  ### RandomGram
1034
1038
 
1035
1039
  This plugin was submitted by @alduhoo. It reads a rg.txt file if it exists in the user's home directory to populate the next group in the sent exchange field.
1040
+
1041
+ ### UKEI DX
1042
+
1043
+ For the Run exchange macro I'd put '{SNT} # {EXCH}'
1044
+
@@ -1,5 +1,5 @@
1
1
  not1mm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- not1mm/__main__.py,sha256=VN2xTYUff4S5DP523oeLcP5J36FKybvOcSHUpU12MUw,151520
2
+ not1mm/__main__.py,sha256=tFLfbd7kbc4GiR4RKYK3F4DKnohI1SBIiKMsjw67--E,151892
3
3
  not1mm/bandmap.py,sha256=-zu5slsuAm2GmeW8g3yvURzsuQxemwIQfw1HEq8xKHM,29920
4
4
  not1mm/checkwindow.py,sha256=zEHlw40j6Wr3rvKbCQf2lcezCoiZqaBqEvBjQU5aKW0,7630
5
5
  not1mm/fsutils.py,sha256=ukHKxKTeNKxKwqRaJjtzRShL4X5Xl0jRBbADyy3Ifp8,1701
@@ -8,7 +8,7 @@ not1mm/lookupservice.py,sha256=GkY_qHZfrW6XHf8upIoaG4hCFqm0fg6Ganu9ConGrIc,2628
8
8
  not1mm/radio.py,sha256=_b-tSFuDLoBKnABxrsafGQu2p33U-KOubY7-qgLV2yg,5408
9
9
  not1mm/ratewindow.py,sha256=PeFmmXYKA6ikR8AzWB6n5TS_1NoaHLocw4pSdySq_7A,6995
10
10
  not1mm/rtc_service.py,sha256=axAwnCBuTr-QL0YwXtWvg9tjwhcFsiiEZFgFjOofX6k,2816
11
- not1mm/statistics.py,sha256=PtlOUmogW9JSTBlQmMhU6yXl_hoLJquYrdX88Oi-2NA,7644
11
+ not1mm/statistics.py,sha256=YbXBCr8wtmXlF21ojgsh0jY_G-dnCApUFe87JZclZAI,7712
12
12
  not1mm/test.py,sha256=RN71m2S9MPIOJMaoCi0wZhwEhpEZunvtosZxaKahRB4,101
13
13
  not1mm/vfo.py,sha256=3kdSfLHLHAGgSE8b8H9n-jFUg_5L7tvrZt_7YCkdsLo,8945
14
14
  not1mm/voice_keying.py,sha256=HZImqC5NgnyW2nknNYQ3b7I8-6S_hxpq5G4RcIRXn_k,3005
@@ -34,7 +34,7 @@ not1mm/data/k6gte.not1mm-64.png,sha256=6ku45Gq1g5ezh04F07osoKRtanb3e4kbx5XdIEh3N
34
34
  not1mm/data/logwindow.ui,sha256=f7vULj96tHIQuR1nJMyvPHHcmVgzkhv9D1isyojsnFU,1458
35
35
  not1mm/data/logwindowx.ui,sha256=CwpI-h7cI1yqyldH9quKftsdHL5lTyL9ABOcf80nfqc,1632
36
36
  not1mm/data/main.ui,sha256=DNJ7jK_1Dd9SDiiGbdwvXDA0WEKjApdRKqBPYFt7S3c,63737
37
- not1mm/data/new_contest.ui,sha256=7B8l_pCaL43ECvGva5S9_gU6_JoNWFEGBE4-EO6BTBY,24703
37
+ not1mm/data/new_contest.ui,sha256=-EMhmysI9hq3HbMv-SH8bJGzsiW0wOhmRE2iOjqxFQ0,24806
38
38
  not1mm/data/not1mm.html,sha256=c9-mfjMwDt4f5pySUruz2gREW33CQ2_rCddM2z5CZQo,23273
39
39
  not1mm/data/opon.ui,sha256=QDicqAk2lORG2UWsHa6jHlsGn6uzrrI2R4HSAocpPes,2258
40
40
  not1mm/data/pickcontest.ui,sha256=4hPBszCglObThx_eIWtmK9CEcbr7WBjbB1rKZdI-o3I,1707
@@ -118,7 +118,7 @@ not1mm/lib/plugin_common.py,sha256=D1OBjyLmX7zuSPqgTCmHwXzAKA12J_zTQItvyIem-4Y,1
118
118
  not1mm/lib/select_contest.py,sha256=WsptLuwkouIHeocJL3oZ6-eUfEnhpwdc-x7eMZ_TIVM,359
119
119
  not1mm/lib/settings.py,sha256=mXffn8Xaj5KATPQinNBR0V5DbHWQPsRfh24_axWGYuk,15254
120
120
  not1mm/lib/super_check_partial.py,sha256=hwT2NRwobu0PLDyw6ltmbmcAtGBD02CKGFbgGWjXMqA,2334
121
- not1mm/lib/version.py,sha256=NA-5bEubD0W-8k5VFfCmY_3Gl8_LkxNwflNMKAbDXTo,47
121
+ not1mm/lib/version.py,sha256=lbRD-owMDb7rKcR3mQWVmU6ChK_06HlEYDAkRCUHqd8,48
122
122
  not1mm/lib/versiontest.py,sha256=8vDNptuBBunn-1IGkjNaquehqBYUJyjrPSF8Igmd4_Y,1286
123
123
  not1mm/plugins/10_10_fall_cw.py,sha256=oJh3JKqjOpnWElSlZpiQ631UnaOd8qra5s9bl_QoInk,14783
124
124
  not1mm/plugins/10_10_spring_cw.py,sha256=p7dSDtbFK0e6Xouw2V6swYn3VFVgHKyx4IfRWyBjMZY,14786
@@ -172,11 +172,12 @@ not1mm/plugins/ref_cw.py,sha256=SY-U-DSyhkTFrsQ6ZLYAt0jTWKa8z05rIZiQ8sTQC-U,2138
172
172
  not1mm/plugins/ref_ssb.py,sha256=cUFUtbe7-5rwZZHEzpPnaIAnwrwayqBvtgctxQDF5Gw,21592
173
173
  not1mm/plugins/spdx.py,sha256=O_PhTaWdjaV29hj2G8tUK3m6GNx8f40hO1JAF-olLMg,15909
174
174
  not1mm/plugins/stew_perry_topband.py,sha256=3U-Dr28haBTqTaZWLiC1qHQBmLsLENDL-ihyddPpJbg,15403
175
+ not1mm/plugins/ukeidx.py,sha256=0ABGW7_9Ui0Rgr8mkPBxOJokAIerM1a4-HWnl6VsnV8,19105
175
176
  not1mm/plugins/weekly_rtty.py,sha256=C8Xs3Q5UgSYx-mFFar8BVARWtmqlyrbeC98Ubzb4UN8,20128
176
177
  not1mm/plugins/winter_field_day.py,sha256=hmAMgkdqIXtnCNyUp8J9Bb8liN8wj10wps6ROuG-Bok,15284
177
- not1mm-25.4.7.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
178
- not1mm-25.4.7.dist-info/METADATA,sha256=B9oqzlPf74X08weJrQef3ruQZG9qQKrgNVukCqSskfA,37367
179
- not1mm-25.4.7.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
180
- not1mm-25.4.7.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
181
- not1mm-25.4.7.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
182
- not1mm-25.4.7.dist-info/RECORD,,
178
+ not1mm-25.4.9.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
179
+ not1mm-25.4.9.dist-info/METADATA,sha256=Lrk0LmsoyTv2hyw5_Kl8yGDeWZkyPe6hMnYbGF2WSw8,37550
180
+ not1mm-25.4.9.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
181
+ not1mm-25.4.9.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
182
+ not1mm-25.4.9.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
183
+ not1mm-25.4.9.dist-info/RECORD,,