not1mm 23.3.25__tar.gz → 23.3.27__tar.gz

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 (63) hide show
  1. {not1mm-23.3.25 → not1mm-23.3.27}/PKG-INFO +11 -1
  2. {not1mm-23.3.25 → not1mm-23.3.27}/README.md +10 -0
  3. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/__main__.py +17 -125
  4. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/database.py +24 -0
  5. not1mm-23.3.27/not1mm/lib/version.py +2 -0
  6. not1mm-23.3.27/not1mm/plugins/cq_wpx_cw.py +389 -0
  7. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/cq_wpx_ssb.py +138 -4
  8. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm.egg-info/PKG-INFO +11 -1
  9. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm.egg-info/SOURCES.txt +1 -0
  10. {not1mm-23.3.25 → not1mm-23.3.27}/pyproject.toml +1 -1
  11. not1mm-23.3.25/not1mm/lib/version.py +0 -2
  12. {not1mm-23.3.25 → not1mm-23.3.27}/LICENSE +0 -0
  13. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/__init__.py +0 -0
  14. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/Combinear.qss +0 -0
  15. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/JetBrainsMono-Regular.ttf +0 -0
  16. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/MASTER.SCP +0 -0
  17. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/check.png +0 -0
  18. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/contests.sql +0 -0
  19. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/cty.json +0 -0
  20. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/cwmacros.txt +0 -0
  21. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/editcontact.ui +0 -0
  22. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/editmacro.ui +0 -0
  23. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/greendot.png +0 -0
  24. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/k6gte-not1mm.desktop +0 -0
  25. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/k6gte.not1mm-128.png +0 -0
  26. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/k6gte.not1mm-32.png +0 -0
  27. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/k6gte.not1mm-64.png +0 -0
  28. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/logwindow.ui +0 -0
  29. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/main.ui +0 -0
  30. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/opon.ui +0 -0
  31. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/reddot.png +0 -0
  32. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/settings.ui +0 -0
  33. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/data/use_qrz_dialog.ui +0 -0
  34. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/__init__.py +0 -0
  35. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/cat_interface.py +0 -0
  36. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/cwinterface.py +0 -0
  37. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/edit_contact.py +0 -0
  38. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/edit_macro.py +0 -0
  39. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/edit_opon.py +0 -0
  40. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/edit_settings.py +0 -0
  41. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/ham_utility.py +0 -0
  42. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/lookup.py +0 -0
  43. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/multicast.py +0 -0
  44. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/n1mm.py +0 -0
  45. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/lib/qrz_dialog.py +0 -0
  46. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/logwindow.py +0 -0
  47. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/__init__.py +0 -0
  48. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/arrl_dx_cw.py +0 -0
  49. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/arrl_dx_phone.py +0 -0
  50. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/arrl_field_day.py +0 -0
  51. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/arrl_rtty_ru.py +0 -0
  52. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/arrl_ss_cw.py +0 -0
  53. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/arrl_ss_phone.py +0 -0
  54. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/cqww_dx_cw.py +0 -0
  55. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/cqww_dx_ssb.py +0 -0
  56. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/general_logging.py +0 -0
  57. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/plugins/winter_field_day.py +0 -0
  58. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm/test.py +0 -0
  59. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm.egg-info/dependency_links.txt +0 -0
  60. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm.egg-info/entry_points.txt +0 -0
  61. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm.egg-info/requires.txt +0 -0
  62. {not1mm-23.3.25 → not1mm-23.3.27}/not1mm.egg-info/top_level.txt +0 -0
  63. {not1mm-23.3.25 → not1mm-23.3.27}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: not1mm
3
- Version: 23.3.25
3
+ Version: 23.3.27
4
4
  Summary: NOT1MM Logger
5
5
  Author-email: Michael Bridak <michael.bridak@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/mbridak/not1mm
@@ -40,6 +40,7 @@ License-File: LICENSE
40
40
  - [Log Display](#log-display)
41
41
  - [Editing a contact](#editing-a-contact)
42
42
  - [Cabrillo](#cabrillo)
43
+ - [ADIF](#adif)
43
44
  - [Dupe checking](#dupe-checking)
44
45
  - [CAT](#cat)
45
46
 
@@ -70,6 +71,7 @@ Feature complete.
70
71
 
71
72
  ## Changes of note
72
73
 
74
+ - [23-3-27] Fix cursor behaviour when editing text in callsign field.
73
75
  - [23-3-25] Fix minimum call length. Fix cabrillo tag. Add adif output.
74
76
  - [23-3-24] Added dupe checking. Added CAT check for flrig or rigctld. Added online flag for flrig.
75
77
  - [23-3-23] Added most of Cabrillo generation. Plan to test it this weekends CQ WPX SSB.
@@ -193,6 +195,14 @@ So for me it would be:
193
195
 
194
196
  K6GTE_CQ-WPX-SSB.log
195
197
 
198
+ ## ADIF
199
+
200
+ `File` > `Generate ADIF`
201
+
202
+ Boom... ADIF
203
+
204
+ `StationCall`_`ContestName`.adi
205
+
196
206
  ## Dupe checking
197
207
 
198
208
  Added dupe checking. Big Red 'Dupe' will appear if it's a dupe...
@@ -21,6 +21,7 @@
21
21
  - [Log Display](#log-display)
22
22
  - [Editing a contact](#editing-a-contact)
23
23
  - [Cabrillo](#cabrillo)
24
+ - [ADIF](#adif)
24
25
  - [Dupe checking](#dupe-checking)
25
26
  - [CAT](#cat)
26
27
 
@@ -51,6 +52,7 @@ Feature complete.
51
52
 
52
53
  ## Changes of note
53
54
 
55
+ - [23-3-27] Fix cursor behaviour when editing text in callsign field.
54
56
  - [23-3-25] Fix minimum call length. Fix cabrillo tag. Add adif output.
55
57
  - [23-3-24] Added dupe checking. Added CAT check for flrig or rigctld. Added online flag for flrig.
56
58
  - [23-3-23] Added most of Cabrillo generation. Plan to test it this weekends CQ WPX SSB.
@@ -174,6 +176,14 @@ So for me it would be:
174
176
 
175
177
  K6GTE_CQ-WPX-SSB.log
176
178
 
179
+ ## ADIF
180
+
181
+ `File` > `Generate ADIF`
182
+
183
+ Boom... ADIF
184
+
185
+ `StationCall`_`ContestName`.adi
186
+
177
187
  ## Dupe checking
178
188
 
179
189
  Added dupe checking. Big Red 'Dupe' will appear if it's a dupe...
@@ -663,7 +663,7 @@ class MainWindow(QtWidgets.QMainWindow):
663
663
 
664
664
  def select_contest(self):
665
665
  """Load contest"""
666
- self.contest = doimp("cq_wpx_ssb")
666
+ self.contest = doimp("cq_wpx_cw")
667
667
  logger.debug("Loaded Contest Name = %s", self.contest.name)
668
668
  self.contest.init_contest(self)
669
669
 
@@ -984,10 +984,12 @@ class MainWindow(QtWidgets.QMainWindow):
984
984
  """Called when text in the callsign field has changed"""
985
985
  text = self.callsign.text()
986
986
  text = text.upper()
987
- stripped_text = text.strip()
987
+ position = self.callsign.cursorPosition()
988
+ stripped_text = text.strip().replace(" ", "")
988
989
  self.callsign.setText(stripped_text)
990
+ self.callsign.setCursorPosition(position)
989
991
 
990
- if text[-1:] == " ":
992
+ if " " in text:
991
993
  if stripped_text == "CW":
992
994
  self.setmode("CW")
993
995
  self.radio_state["mode"] = "CW"
@@ -1113,9 +1115,18 @@ class MainWindow(QtWidgets.QMainWindow):
1113
1115
  """Checks if a callsign is a dupe on current band/mode."""
1114
1116
  band = float(get_logged_band(str(self.radio_state.get("vfoa", 0.0))))
1115
1117
  mode = self.radio_state.get("mode", "")
1116
- debugline = f"Call: {call} Band: {band} Mode: {mode}"
1118
+ debugline = (
1119
+ f"Call: {call} Band: {band} Mode: {mode} Dupetype: {self.contest.dupe_type}"
1120
+ )
1117
1121
  logger.debug("%s", debugline)
1118
- result = self.database.check_dupe_on_band_mode(call, band, mode)
1122
+ if self.contest.dupe_type == 1:
1123
+ result = self.database.check_dupe(call)
1124
+ if self.contest.dupe_type == 2:
1125
+ result = self.database.check_dupe_on_band(call, band)
1126
+ if self.contest.dupe_type == 3:
1127
+ result = self.database.check_dupe_on_band_mode(call, band, mode)
1128
+ if self.contest.dupe_type == 4:
1129
+ result = {"isdupe": False}
1119
1130
  debugline = f"{result}"
1120
1131
  logger.debug("%s", debugline)
1121
1132
  return result.get("isdupe", False)
@@ -1242,126 +1253,7 @@ class MainWindow(QtWidgets.QMainWindow):
1242
1253
  """Generates Cabrillo file. Maybe."""
1243
1254
  # https://www.cqwpx.com/cabrillo.htm
1244
1255
  logger.debug("******Cabrillo*****")
1245
- filename = (
1246
- str(Path.home())
1247
- + "/"
1248
- + f"{self.pref.get('callsign').upper()}_{self.contest.cabrillo_name}.log"
1249
- )
1250
- logger.debug("%s", filename)
1251
- log = self.database.fetch_all_contacts_asc()
1252
- try:
1253
- with open(filename, "w", encoding="ascii") as file_descriptor:
1254
- print("START-OF-LOG: 3.0", end="\r\n", file=file_descriptor)
1255
- print(
1256
- f"CREATED-BY: Not1MM v{__version__}",
1257
- end="\r\n",
1258
- file=file_descriptor,
1259
- )
1260
- print(
1261
- f"CONTEST: {self.contest.cabrillo_name}",
1262
- end="\r\n",
1263
- file=file_descriptor,
1264
- )
1265
- print(
1266
- f"CALLSIGN: {self.pref.get('callsign','')}",
1267
- end="\r\n",
1268
- file=file_descriptor,
1269
- )
1270
- print(
1271
- f"LOCATION: {self.pref.get('section', '')}",
1272
- end="\r\n",
1273
- file=file_descriptor,
1274
- )
1275
- # print(
1276
- # f"ARRL-SECTION: {self.pref.get('section', '')}",
1277
- # end="\r\n",
1278
- # file=file_descriptor,
1279
- # )
1280
- # CATEGORY-OPERATOR: SINGLE-OP
1281
- # CATEGORY-ASSISTED: NON-ASSISTED
1282
- # CATEGORY-BAND: ALL
1283
- # CATEGORY-MODE: SSB
1284
- # CATEGORY-TRANSMITTER: ONE
1285
- # CATEGORY-OVERLAY: CLASSIC
1286
- # GRID-LOCATOR: DM13at
1287
- print(
1288
- f"CATEGORY: {None}",
1289
- end="\r\n",
1290
- file=file_descriptor,
1291
- )
1292
- print("CATEGORY-POWER: ", end="\r\n", file=file_descriptor)
1293
-
1294
- print(
1295
- f"CLAIMED-SCORE: {self.contest.calc_score(self)}",
1296
- end="\r\n",
1297
- file=file_descriptor,
1298
- )
1299
- print(
1300
- "OPERATORS: ",
1301
- end="\r\n",
1302
- file=file_descriptor,
1303
- )
1304
- print(
1305
- f"NAME: {self.pref.get('name', '')}",
1306
- end="\r\n",
1307
- file=file_descriptor,
1308
- )
1309
- print(
1310
- f"ADDRESS: {self.pref.get('address1', '')}",
1311
- end="\r\n",
1312
- file=file_descriptor,
1313
- )
1314
- print(
1315
- f"ADDRESS-CITY: {self.pref.get('city', '')}",
1316
- end="\r\n",
1317
- file=file_descriptor,
1318
- )
1319
- print(
1320
- f"ADDRESS-STATE-PROVINCE: {self.pref.get('state', '')}",
1321
- end="\r\n",
1322
- file=file_descriptor,
1323
- )
1324
- print(
1325
- f"ADDRESS-POSTALCODE: {self.pref.get('zip', '')}",
1326
- end="\r\n",
1327
- file=file_descriptor,
1328
- )
1329
- print(
1330
- f"ADDRESS-COUNTRY: {self.pref.get('country', '')}",
1331
- end="\r\n",
1332
- file=file_descriptor,
1333
- )
1334
- print(
1335
- f"EMAIL: {self.pref.get('email', '')}",
1336
- end="\r\n",
1337
- file=file_descriptor,
1338
- )
1339
- for contact in log:
1340
- the_date_and_time = contact.get("TS", "")
1341
- mode = contact.get("Mode", "")
1342
- if mode == "LSB" or mode == "USB":
1343
- mode = "PH"
1344
- frequency = str(int(contact.get("Freq", "0"))).rjust(5)
1345
-
1346
- loggeddate = the_date_and_time[:10]
1347
- loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
1348
- print(
1349
- f"QSO: {frequency} {mode} {loggeddate} {loggedtime} "
1350
- f"{contact.get('StationPrefix', '').ljust(13)} "
1351
- f"{str(contact.get('SNT', '')).ljust(3)} "
1352
- f"{str(contact.get('SentNr', '')).ljust(6)} "
1353
- f"{contact.get('Call', '').ljust(13)} "
1354
- f"{str(contact.get('RCV', '')).ljust(3)} "
1355
- f"{str(contact.get('NR', '')).ljust(6)}",
1356
- end="\r\n",
1357
- file=file_descriptor,
1358
- )
1359
- print("END-OF-LOG:", end="\r\n", file=file_descriptor)
1360
- except IOError as exception:
1361
- logger.critical(
1362
- "cabrillo: IO error: %s, writing to %s", exception, filename
1363
- )
1364
- return
1256
+ self.contest.cabrillo(self)
1365
1257
 
1366
1258
 
1367
1259
  def load_fonts_from_dir(directory: str) -> set:
@@ -370,6 +370,30 @@ class DataBase:
370
370
  )
371
371
  return cursor.fetchone()
372
372
 
373
+ def check_dupe_on_band(self, call, band) -> dict:
374
+ """Checks if a call is dupe on band/mode"""
375
+ with sqlite3.connect(self.database) as conn:
376
+ conn.row_factory = self.row_factory
377
+ cursor = conn.cursor()
378
+ print(
379
+ f"select count(*) as isdupe from dxlog where Call = '{call}' and Band = '{band}';"
380
+ )
381
+ cursor.execute(
382
+ f"select count(*) as isdupe from dxlog where Call = '{call}' and Band = '{band}';"
383
+ )
384
+ return cursor.fetchone()
385
+
386
+ def check_dupe(self, call) -> dict:
387
+ """Checks if a call is dupe on band/mode"""
388
+ with sqlite3.connect(self.database) as conn:
389
+ conn.row_factory = self.row_factory
390
+ cursor = conn.cursor()
391
+ print(f"select count(*) as isdupe from dxlog where Call = '{call}';")
392
+ cursor.execute(
393
+ f"select count(*) as isdupe from dxlog where Call = '{call}';"
394
+ )
395
+ return cursor.fetchone()
396
+
373
397
  def fetch_points(self) -> dict:
374
398
  """return points"""
375
399
  with sqlite3.connect(self.database) as conn:
@@ -0,0 +1,2 @@
1
+ """It's the version"""
2
+ __version__ = "23.3.27"
@@ -0,0 +1,389 @@
1
+ """CQ WPX CW plugin"""
2
+
3
+ # pylint: disable=invalid-name
4
+ import logging
5
+ from pathlib import Path
6
+
7
+ from PyQt5 import QtWidgets
8
+
9
+ from not1mm.lib.version import __version__
10
+
11
+ logger = logging.getLogger("__main__")
12
+
13
+ name = "CQ WPX CW"
14
+ cabrillo_name = "CQ-WPX-CW"
15
+ mode = "CW" # CW SSB BOTH RTTY
16
+
17
+ # 1 once per contest, 2 work each band, 3 each band/mode, 4 no dupe checking
18
+ dupe_type = 2
19
+
20
+
21
+ def init_contest(self):
22
+ """setup plugin"""
23
+ set_tab_next(self)
24
+ set_tab_prev(self)
25
+ interface(self)
26
+ self.next_field = self.other_2
27
+
28
+
29
+ def interface(self):
30
+ """Setup user interface"""
31
+ self.field1.show()
32
+ self.field2.show()
33
+ self.field3.show()
34
+ self.field4.show()
35
+ label = self.field3.findChild(QtWidgets.QLabel)
36
+ label.setText("SentNR")
37
+ label = self.field4.findChild(QtWidgets.QLabel)
38
+ label.setText("RcvNR")
39
+
40
+
41
+ def set_tab_next(self):
42
+ """Set TAB Advances"""
43
+ self.tab_next = {
44
+ self.callsign: self.field1.findChild(QtWidgets.QLineEdit),
45
+ self.field1.findChild(QtWidgets.QLineEdit): self.field2.findChild(
46
+ QtWidgets.QLineEdit
47
+ ),
48
+ self.field2.findChild(QtWidgets.QLineEdit): self.field3.findChild(
49
+ QtWidgets.QLineEdit
50
+ ),
51
+ self.field3.findChild(QtWidgets.QLineEdit): self.field4.findChild(
52
+ QtWidgets.QLineEdit
53
+ ),
54
+ self.field4.findChild(QtWidgets.QLineEdit): self.callsign,
55
+ }
56
+
57
+
58
+ def set_tab_prev(self):
59
+ """Set TAB Advances"""
60
+ self.tab_prev = {
61
+ self.callsign: self.field4.findChild(QtWidgets.QLineEdit),
62
+ self.field1.findChild(QtWidgets.QLineEdit): self.callsign,
63
+ self.field2.findChild(QtWidgets.QLineEdit): self.field1.findChild(
64
+ QtWidgets.QLineEdit
65
+ ),
66
+ self.field3.findChild(QtWidgets.QLineEdit): self.field2.findChild(
67
+ QtWidgets.QLineEdit
68
+ ),
69
+ self.field4.findChild(QtWidgets.QLineEdit): self.field3.findChild(
70
+ QtWidgets.QLineEdit
71
+ ),
72
+ }
73
+
74
+
75
+ def set_contact_vars(self):
76
+ """Contest Specific"""
77
+ self.contact["SNT"] = self.sent.text()
78
+ self.contact["RCV"] = self.receive.text()
79
+ self.contact["SentNr"] = self.other_1.text()
80
+ self.contact["NR"] = self.other_2.text()
81
+ if self.contact.get("WPXPrefix"):
82
+ result = self.database.fetch_wpx_exists(self.contact.get("WPXPrefix", ""))
83
+ if result.get("wpx_count"):
84
+ self.contact["IsMultiplier1"] = 0
85
+ else:
86
+ self.contact["IsMultiplier1"] = 1
87
+
88
+
89
+ def prefill(self):
90
+ """Fill SentNR"""
91
+ result = self.database.get_serial()
92
+ serial_nr = str(result.get("serial_nr", "1"))
93
+ if serial_nr == "None":
94
+ serial_nr = "1"
95
+ field = self.field3.findChild(QtWidgets.QLineEdit)
96
+ if len(field.text()) == 0:
97
+ field.setText(serial_nr)
98
+
99
+
100
+ def points(self):
101
+ """Calc point"""
102
+ result = self.cty_lookup(self.pref.get("callsign", ""))
103
+ if result:
104
+ for item in result.items():
105
+ mycountry = item[1].get("entity", "")
106
+ mycontinent = item[1].get("continent", "")
107
+ result = self.cty_lookup(self.contact.get("Call", ""))
108
+ band = int(int(float(self.contact.get("Freq"))) / 1000)
109
+ if result:
110
+ for item in result.items():
111
+ entity = item[1].get("entity", "")
112
+ continent = item[1].get("continent", "")
113
+ if mycountry.upper() == entity.upper():
114
+ return 1
115
+ if mycontinent and continent == "NA":
116
+ if band in [28, 21, 14]:
117
+ return 2
118
+ return 4
119
+ if mycontinent == continent:
120
+ if band in [28, 21, 14]:
121
+ return 1
122
+ return 2
123
+ if band in [28, 21, 14]:
124
+ return 3
125
+ return 6
126
+ return 0
127
+
128
+
129
+ def show_mults(self):
130
+ """Return display string for mults"""
131
+ result = self.database.fetch_wpx_count()
132
+ if result:
133
+ return int(result.get("wpx_count", 0))
134
+ return 0
135
+
136
+
137
+ def show_qso(self):
138
+ """Return qso count"""
139
+ result = self.database.fetch_qso_count()
140
+ if result:
141
+ return int(result.get("qsos", 0))
142
+ return 0
143
+
144
+
145
+ def get_points(self):
146
+ """Return raw points before mults"""
147
+ result = self.database.fetch_points()
148
+ if result:
149
+ return int(result.get("Points", 0))
150
+ return 0
151
+
152
+
153
+ def calc_score(self):
154
+ """Return calculated score"""
155
+ result = self.database.fetch_points()
156
+ if result is not None:
157
+ score = result.get("Points", "0")
158
+ if score is None:
159
+ score = "0"
160
+ contest_points = int(score)
161
+ result = self.database.fetch_wpx_count()
162
+ mults = int(result.get("wpx_count", 0))
163
+ return contest_points * mults
164
+ return 0
165
+
166
+
167
+ def adif(self):
168
+ """
169
+ Creates an ADIF file of the contacts made.
170
+ """
171
+ filename = (
172
+ str(Path.home())
173
+ + "/"
174
+ + f"{self.pref.get('callsign').upper()}_{cabrillo_name}.adi"
175
+ )
176
+ log = self.database.fetch_all_contacts_asc()
177
+ try:
178
+ with open(filename, "w", encoding="utf-8") as file_descriptor:
179
+ print("<ADIF_VER:5>2.2.0", end="\r\n", file=file_descriptor)
180
+ print("<EOH>", end="\r\n", file=file_descriptor)
181
+ for contact in log:
182
+
183
+ hiscall = contact.get("Call", "")
184
+ the_date_and_time = contact.get("TS")
185
+ # band = contact.get("Band")
186
+ themode = contact.get("Mode")
187
+ frequency = str(contact.get("Freq", 0) / 1000)
188
+ sentrst = contact.get("SNT", "")
189
+ rcvrst = contact.get("RCV", "")
190
+ sentnr = str(contact.get("SentNr", "59"))
191
+ rcvnr = str(contact.get("NR", "59"))
192
+ grid = contact.get("GridSquare", "")
193
+ comment = contact.get("ContestName", "")
194
+ loggeddate = the_date_and_time[:10]
195
+ loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
196
+ print(
197
+ f"<QSO_DATE:{len(''.join(loggeddate.split('-')))}:d>"
198
+ f"{''.join(loggeddate.split('-'))}",
199
+ end="\r\n",
200
+ file=file_descriptor,
201
+ )
202
+ print(
203
+ f"<TIME_ON:{len(loggedtime)}>{loggedtime}",
204
+ end="\r\n",
205
+ file=file_descriptor,
206
+ )
207
+ print(
208
+ f"<CALL:{len(hiscall)}>{hiscall}",
209
+ end="\r\n",
210
+ file=file_descriptor,
211
+ )
212
+ print(
213
+ f"<MODE:{len(themode)}>{themode}", end="\r\n", file=file_descriptor
214
+ )
215
+ # print(
216
+ # f"<BAND:{len(band + 'M')}>{band + 'M'}",
217
+ # end="\r\n",
218
+ # file=file_descriptor,
219
+ # )
220
+ try:
221
+ print(
222
+ f"<FREQ:{len(frequency)}>{frequency}",
223
+ end="\r\n",
224
+ file=file_descriptor,
225
+ )
226
+ except TypeError:
227
+ pass # This is bad form... I can't remember why this is in a try block
228
+
229
+ print(
230
+ f"<RST_SENT:{len(sentrst)}>{sentrst}",
231
+ end="\r\n",
232
+ file=file_descriptor,
233
+ )
234
+ print(
235
+ f"<RST_RCVD:{len(rcvrst)}>{rcvrst}",
236
+ end="\r\n",
237
+ file=file_descriptor,
238
+ )
239
+
240
+ print(
241
+ f"<STX_STRING:{len(sentnr)}>{sentnr}",
242
+ end="\r\n",
243
+ file=file_descriptor,
244
+ )
245
+ print(
246
+ f"<SRX_STRING:{len(rcvnr)}>{rcvnr}",
247
+ end="\r\n",
248
+ file=file_descriptor,
249
+ )
250
+ if len(grid) > 1:
251
+ print(
252
+ f"<GRIDSQUARE:{len(grid)}>{grid}",
253
+ end="\r\n",
254
+ file=file_descriptor,
255
+ )
256
+
257
+ print(
258
+ f"<COMMENT:{len(comment)}>{comment}",
259
+ end="\r\n",
260
+ file=file_descriptor,
261
+ )
262
+ print("<EOR>", end="\r\n", file=file_descriptor)
263
+ print("", end="\r\n", file=file_descriptor)
264
+ except IOError:
265
+ ...
266
+
267
+
268
+ def cabrillo(self):
269
+ """Generates Cabrillo file. Maybe."""
270
+ # https://www.cqwpx.com/cabrillo.htm
271
+ logger.debug("******Cabrillo*****")
272
+ filename = (
273
+ str(Path.home())
274
+ + "/"
275
+ + f"{self.pref.get('callsign').upper()}_{cabrillo_name}.log"
276
+ )
277
+ logger.debug("%s", filename)
278
+ log = self.database.fetch_all_contacts_asc()
279
+ try:
280
+ with open(filename, "w", encoding="ascii") as file_descriptor:
281
+ print("START-OF-LOG: 3.0", end="\r\n", file=file_descriptor)
282
+ print(
283
+ f"CREATED-BY: Not1MM v{__version__}",
284
+ end="\r\n",
285
+ file=file_descriptor,
286
+ )
287
+ print(
288
+ f"CONTEST: {cabrillo_name}",
289
+ end="\r\n",
290
+ file=file_descriptor,
291
+ )
292
+ print(
293
+ f"CALLSIGN: {self.pref.get('callsign','')}",
294
+ end="\r\n",
295
+ file=file_descriptor,
296
+ )
297
+ print(
298
+ f"LOCATION: {self.pref.get('section', '')}",
299
+ end="\r\n",
300
+ file=file_descriptor,
301
+ )
302
+ # print(
303
+ # f"ARRL-SECTION: {self.pref.get('section', '')}",
304
+ # end="\r\n",
305
+ # file=file_descriptor,
306
+ # )
307
+ # CATEGORY-OPERATOR: SINGLE-OP
308
+ # CATEGORY-ASSISTED: NON-ASSISTED
309
+ # CATEGORY-BAND: ALL
310
+ # CATEGORY-MODE: SSB
311
+ # CATEGORY-TRANSMITTER: ONE
312
+ # CATEGORY-OVERLAY: CLASSIC
313
+ # GRID-LOCATOR: DM13at
314
+ print(
315
+ f"CATEGORY: {None}",
316
+ end="\r\n",
317
+ file=file_descriptor,
318
+ )
319
+ print("CATEGORY-POWER: ", end="\r\n", file=file_descriptor)
320
+
321
+ print(
322
+ f"CLAIMED-SCORE: {calc_score(self)}",
323
+ end="\r\n",
324
+ file=file_descriptor,
325
+ )
326
+ print(
327
+ "OPERATORS: ",
328
+ end="\r\n",
329
+ file=file_descriptor,
330
+ )
331
+ print(
332
+ f"NAME: {self.pref.get('name', '')}",
333
+ end="\r\n",
334
+ file=file_descriptor,
335
+ )
336
+ print(
337
+ f"ADDRESS: {self.pref.get('address1', '')}",
338
+ end="\r\n",
339
+ file=file_descriptor,
340
+ )
341
+ print(
342
+ f"ADDRESS-CITY: {self.pref.get('city', '')}",
343
+ end="\r\n",
344
+ file=file_descriptor,
345
+ )
346
+ print(
347
+ f"ADDRESS-STATE-PROVINCE: {self.pref.get('state', '')}",
348
+ end="\r\n",
349
+ file=file_descriptor,
350
+ )
351
+ print(
352
+ f"ADDRESS-POSTALCODE: {self.pref.get('zip', '')}",
353
+ end="\r\n",
354
+ file=file_descriptor,
355
+ )
356
+ print(
357
+ f"ADDRESS-COUNTRY: {self.pref.get('country', '')}",
358
+ end="\r\n",
359
+ file=file_descriptor,
360
+ )
361
+ print(
362
+ f"EMAIL: {self.pref.get('email', '')}",
363
+ end="\r\n",
364
+ file=file_descriptor,
365
+ )
366
+ for contact in log:
367
+ the_date_and_time = contact.get("TS", "")
368
+ themode = contact.get("Mode", "")
369
+ if themode == "LSB" or themode == "USB":
370
+ themode = "PH"
371
+ frequency = str(int(contact.get("Freq", "0"))).rjust(5)
372
+
373
+ loggeddate = the_date_and_time[:10]
374
+ loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
375
+ print(
376
+ f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
377
+ f"{contact.get('StationPrefix', '').ljust(13)} "
378
+ f"{str(contact.get('SNT', '')).ljust(3)} "
379
+ f"{str(contact.get('SentNr', '')).ljust(6)} "
380
+ f"{contact.get('Call', '').ljust(13)} "
381
+ f"{str(contact.get('RCV', '')).ljust(3)} "
382
+ f"{str(contact.get('NR', '')).ljust(6)}",
383
+ end="\r\n",
384
+ file=file_descriptor,
385
+ )
386
+ print("END-OF-LOG:", end="\r\n", file=file_descriptor)
387
+ except IOError as exception:
388
+ logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
389
+ return
@@ -1,15 +1,21 @@
1
1
  """CQ WPX SSB plugin"""
2
2
 
3
3
  # pylint: disable=invalid-name
4
+ import logging
5
+ from pathlib import Path
4
6
 
5
7
  from PyQt5 import QtWidgets
6
8
 
9
+ from not1mm.lib.version import __version__
10
+
11
+ logger = logging.getLogger("__main__")
12
+
7
13
  name = "CQ WPX SSB"
8
14
  cabrillo_name = "CQ-WPX-SSB"
9
15
  mode = "SSB" # CW SSB BOTH RTTY
10
16
 
11
17
  # 1 once per contest, 2 work each band, 3 each band/mode, 4 no dupe checking
12
- dupe_type = 4
18
+ dupe_type = 2
13
19
 
14
20
 
15
21
  def init_contest(self):
@@ -162,17 +168,21 @@ def adif(self):
162
168
  """
163
169
  Creates an ADIF file of the contacts made.
164
170
  """
165
- logname = "cqwpxssb.adi"
171
+ filename = (
172
+ str(Path.home())
173
+ + "/"
174
+ + f"{self.pref.get('callsign').upper()}_{cabrillo_name}.adi"
175
+ )
166
176
  log = self.database.fetch_all_contacts_asc()
167
177
  try:
168
- with open(logname, "w", encoding="utf-8") as file_descriptor:
178
+ with open(filename, "w", encoding="utf-8") as file_descriptor:
169
179
  print("<ADIF_VER:5>2.2.0", end="\r\n", file=file_descriptor)
170
180
  print("<EOH>", end="\r\n", file=file_descriptor)
171
181
  for contact in log:
172
182
 
173
183
  hiscall = contact.get("Call", "")
174
184
  the_date_and_time = contact.get("TS")
175
- band = contact.get("Band")
185
+ # band = contact.get("Band")
176
186
  themode = contact.get("Mode")
177
187
  frequency = str(contact.get("Freq", 0) / 1000)
178
188
  sentrst = contact.get("SNT", "")
@@ -253,3 +263,127 @@ def adif(self):
253
263
  print("", end="\r\n", file=file_descriptor)
254
264
  except IOError:
255
265
  ...
266
+
267
+
268
+ def cabrillo(self):
269
+ """Generates Cabrillo file. Maybe."""
270
+ # https://www.cqwpx.com/cabrillo.htm
271
+ logger.debug("******Cabrillo*****")
272
+ filename = (
273
+ str(Path.home())
274
+ + "/"
275
+ + f"{self.pref.get('callsign').upper()}_{cabrillo_name}.log"
276
+ )
277
+ logger.debug("%s", filename)
278
+ log = self.database.fetch_all_contacts_asc()
279
+ try:
280
+ with open(filename, "w", encoding="ascii") as file_descriptor:
281
+ print("START-OF-LOG: 3.0", end="\r\n", file=file_descriptor)
282
+ print(
283
+ f"CREATED-BY: Not1MM v{__version__}",
284
+ end="\r\n",
285
+ file=file_descriptor,
286
+ )
287
+ print(
288
+ f"CONTEST: {cabrillo_name}",
289
+ end="\r\n",
290
+ file=file_descriptor,
291
+ )
292
+ print(
293
+ f"CALLSIGN: {self.pref.get('callsign','')}",
294
+ end="\r\n",
295
+ file=file_descriptor,
296
+ )
297
+ print(
298
+ f"LOCATION: {self.pref.get('section', '')}",
299
+ end="\r\n",
300
+ file=file_descriptor,
301
+ )
302
+ # print(
303
+ # f"ARRL-SECTION: {self.pref.get('section', '')}",
304
+ # end="\r\n",
305
+ # file=file_descriptor,
306
+ # )
307
+ # CATEGORY-OPERATOR: SINGLE-OP
308
+ # CATEGORY-ASSISTED: NON-ASSISTED
309
+ # CATEGORY-BAND: ALL
310
+ # CATEGORY-MODE: SSB
311
+ # CATEGORY-TRANSMITTER: ONE
312
+ # CATEGORY-OVERLAY: CLASSIC
313
+ # GRID-LOCATOR: DM13at
314
+ print(
315
+ f"CATEGORY: {None}",
316
+ end="\r\n",
317
+ file=file_descriptor,
318
+ )
319
+ print("CATEGORY-POWER: ", end="\r\n", file=file_descriptor)
320
+
321
+ print(
322
+ f"CLAIMED-SCORE: {calc_score(self)}",
323
+ end="\r\n",
324
+ file=file_descriptor,
325
+ )
326
+ print(
327
+ "OPERATORS: ",
328
+ end="\r\n",
329
+ file=file_descriptor,
330
+ )
331
+ print(
332
+ f"NAME: {self.pref.get('name', '')}",
333
+ end="\r\n",
334
+ file=file_descriptor,
335
+ )
336
+ print(
337
+ f"ADDRESS: {self.pref.get('address1', '')}",
338
+ end="\r\n",
339
+ file=file_descriptor,
340
+ )
341
+ print(
342
+ f"ADDRESS-CITY: {self.pref.get('city', '')}",
343
+ end="\r\n",
344
+ file=file_descriptor,
345
+ )
346
+ print(
347
+ f"ADDRESS-STATE-PROVINCE: {self.pref.get('state', '')}",
348
+ end="\r\n",
349
+ file=file_descriptor,
350
+ )
351
+ print(
352
+ f"ADDRESS-POSTALCODE: {self.pref.get('zip', '')}",
353
+ end="\r\n",
354
+ file=file_descriptor,
355
+ )
356
+ print(
357
+ f"ADDRESS-COUNTRY: {self.pref.get('country', '')}",
358
+ end="\r\n",
359
+ file=file_descriptor,
360
+ )
361
+ print(
362
+ f"EMAIL: {self.pref.get('email', '')}",
363
+ end="\r\n",
364
+ file=file_descriptor,
365
+ )
366
+ for contact in log:
367
+ the_date_and_time = contact.get("TS", "")
368
+ themode = contact.get("Mode", "")
369
+ if themode == "LSB" or themode == "USB":
370
+ themode = "PH"
371
+ frequency = str(int(contact.get("Freq", "0"))).rjust(5)
372
+
373
+ loggeddate = the_date_and_time[:10]
374
+ loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
375
+ print(
376
+ f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
377
+ f"{contact.get('StationPrefix', '').ljust(13)} "
378
+ f"{str(contact.get('SNT', '')).ljust(3)} "
379
+ f"{str(contact.get('SentNr', '')).ljust(6)} "
380
+ f"{contact.get('Call', '').ljust(13)} "
381
+ f"{str(contact.get('RCV', '')).ljust(3)} "
382
+ f"{str(contact.get('NR', '')).ljust(6)}",
383
+ end="\r\n",
384
+ file=file_descriptor,
385
+ )
386
+ print("END-OF-LOG:", end="\r\n", file=file_descriptor)
387
+ except IOError as exception:
388
+ logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
389
+ return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: not1mm
3
- Version: 23.3.25
3
+ Version: 23.3.27
4
4
  Summary: NOT1MM Logger
5
5
  Author-email: Michael Bridak <michael.bridak@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/mbridak/not1mm
@@ -40,6 +40,7 @@ License-File: LICENSE
40
40
  - [Log Display](#log-display)
41
41
  - [Editing a contact](#editing-a-contact)
42
42
  - [Cabrillo](#cabrillo)
43
+ - [ADIF](#adif)
43
44
  - [Dupe checking](#dupe-checking)
44
45
  - [CAT](#cat)
45
46
 
@@ -70,6 +71,7 @@ Feature complete.
70
71
 
71
72
  ## Changes of note
72
73
 
74
+ - [23-3-27] Fix cursor behaviour when editing text in callsign field.
73
75
  - [23-3-25] Fix minimum call length. Fix cabrillo tag. Add adif output.
74
76
  - [23-3-24] Added dupe checking. Added CAT check for flrig or rigctld. Added online flag for flrig.
75
77
  - [23-3-23] Added most of Cabrillo generation. Plan to test it this weekends CQ WPX SSB.
@@ -193,6 +195,14 @@ So for me it would be:
193
195
 
194
196
  K6GTE_CQ-WPX-SSB.log
195
197
 
198
+ ## ADIF
199
+
200
+ `File` > `Generate ADIF`
201
+
202
+ Boom... ADIF
203
+
204
+ `StationCall`_`ContestName`.adi
205
+
196
206
  ## Dupe checking
197
207
 
198
208
  Added dupe checking. Big Red 'Dupe' will appear if it's a dupe...
@@ -52,6 +52,7 @@ not1mm/plugins/arrl_field_day.py
52
52
  not1mm/plugins/arrl_rtty_ru.py
53
53
  not1mm/plugins/arrl_ss_cw.py
54
54
  not1mm/plugins/arrl_ss_phone.py
55
+ not1mm/plugins/cq_wpx_cw.py
55
56
  not1mm/plugins/cq_wpx_ssb.py
56
57
  not1mm/plugins/cqww_dx_cw.py
57
58
  not1mm/plugins/cqww_dx_ssb.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "not1mm"
7
- version = "23.3.25"
7
+ version = "23.3.27"
8
8
  description = "NOT1MM Logger"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,2 +0,0 @@
1
- """It's the version"""
2
- __version__ = "23.3.25"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes