not1mm 23.7.29__py3-none-any.whl → 23.8.6__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
@@ -3,6 +3,7 @@
3
3
  NOT1MM Logger
4
4
  """
5
5
  # pylint: disable=unused-import, c-extension-no-member, no-member, invalid-name, too-many-lines, no-name-in-module
6
+ # pylint: disable=logging-fstring-interpolation
6
7
 
7
8
  import datetime as dt
8
9
  import importlib
@@ -16,7 +17,6 @@ import socket
16
17
  import subprocess
17
18
  import sys
18
19
  import threading
19
- import time
20
20
  import uuid
21
21
  from datetime import datetime
22
22
  from json import JSONDecodeError, dumps, loads
@@ -25,7 +25,6 @@ from shutil import copyfile
25
25
 
26
26
  import notctyparser
27
27
  import psutil
28
- import requests
29
28
  import sounddevice as sd
30
29
  import soundfile as sf
31
30
  from PyQt5 import QtCore, QtGui, QtWidgets, uic
@@ -54,6 +53,7 @@ from not1mm.lib.lookup import HamDBlookup, HamQTH, QRZlookup
54
53
  from not1mm.lib.multicast import Multicast
55
54
  from not1mm.lib.n1mm import N1MM
56
55
  from not1mm.lib.new_contest import NewContest
56
+ from not1mm.lib.super_check_partial import SCP
57
57
  from not1mm.lib.select_contest import SelectContest
58
58
  from not1mm.lib.settings import Settings
59
59
  from not1mm.lib.version import __version__
@@ -77,8 +77,6 @@ from not1mm.lib.versiontest import VersionTest
77
77
  loader = pkgutil.get_loader("not1mm")
78
78
  WORKING_PATH = os.path.dirname(loader.get_filename())
79
79
 
80
- MASTER_SCP_URL = "https://www.supercheckpartial.com/MASTER.SCP"
81
-
82
80
  DATA_PATH = os.environ.get("XDG_DATA_HOME", str(Path.home() / ".local" / "share"))
83
81
  DATA_PATH += "/not1mm"
84
82
 
@@ -232,6 +230,7 @@ class MainWindow(QtWidgets.QMainWindow):
232
230
  self.leftdot.hide()
233
231
  self.rightdot.hide()
234
232
  self.n1mm = N1MM()
233
+ self.mscp = SCP(WORKING_PATH)
235
234
  self.next_field = self.other_2
236
235
  self.dupe_indicator.hide()
237
236
  self.cw_speed.valueChanged.connect(self.cwspeed_spinbox_changed)
@@ -240,6 +239,7 @@ class MainWindow(QtWidgets.QMainWindow):
240
239
  self.actionCommand_Buttons.triggered.connect(self.command_buttons_state_change)
241
240
  self.actionLog_Window.triggered.connect(self.launch_log_window)
242
241
  self.actionBandmap.triggered.connect(self.launch_bandmap_window)
242
+ self.actionCheck_Window.triggered.connect(self.launch_check_window)
243
243
  self.actionRecalculate_Mults.triggered.connect(self.recalculate_mults)
244
244
 
245
245
  self.actionGenerate_Cabrillo.triggered.connect(self.generate_cabrillo)
@@ -383,6 +383,10 @@ class MainWindow(QtWidgets.QMainWindow):
383
383
 
384
384
  def quit_app(self):
385
385
  """doc"""
386
+ cmd = {}
387
+ cmd["cmd"] = "HALT"
388
+ cmd["station"] = platform.node()
389
+ self.multicast_interface.send_as_json(cmd)
386
390
  app.quit()
387
391
 
388
392
  @staticmethod
@@ -421,17 +425,10 @@ class MainWindow(QtWidgets.QMainWindow):
421
425
  self.about_dialog.open()
422
426
 
423
427
  def update_masterscp(self) -> None:
424
- """Update the MASTER.SCP file.
425
- - Returns True if successful
426
- - Otherwise False
427
- """
428
- with requests.Session() as session:
429
- the_request = session.get(MASTER_SCP_URL)
430
- if the_request.status_code == 200:
431
- with open(WORKING_PATH + "/data/MASTER.SCP", "wb+") as file:
432
- file.write(the_request.content)
433
- self.show_message_box("MASTER.SCP file updated.")
434
- return
428
+ """Update the MASTER.SCP file."""
429
+ if self.mscp.update_masterscp():
430
+ self.show_message_box("MASTER.SCP file updated.")
431
+ return
435
432
  self.show_message_box("MASTER.SCP could not be updated.")
436
433
 
437
434
  def edit_configuration_settings(self):
@@ -812,6 +809,11 @@ class MainWindow(QtWidgets.QMainWindow):
812
809
  if not check_process("bandmap.py"):
813
810
  _ = subprocess.Popen([sys.executable, WORKING_PATH + "/bandmap.py"])
814
811
 
812
+ def launch_check_window(self):
813
+ """launch the Log Window"""
814
+ if not check_process("checkwindow.py"):
815
+ _ = subprocess.Popen([sys.executable, WORKING_PATH + "/checkwindow.py"])
816
+
815
817
  def clear_band_indicators(self):
816
818
  """Clear the indicators"""
817
819
  for _, indicators in self.all_mode_indicators.items():
@@ -833,6 +835,10 @@ class MainWindow(QtWidgets.QMainWindow):
833
835
  """
834
836
  Write window size and position to config file
835
837
  """
838
+ cmd = {}
839
+ cmd["cmd"] = "HALT"
840
+ cmd["station"] = platform.node()
841
+ self.multicast_interface.send_as_json(cmd)
836
842
  self.pref["window_width"] = self.size().width()
837
843
  self.pref["window_height"] = self.size().height()
838
844
  self.pref["window_x"] = self.pos().x()
@@ -1901,6 +1907,8 @@ class MainWindow(QtWidgets.QMainWindow):
1901
1907
  stripped_text = text.strip().replace(" ", "")
1902
1908
  self.callsign.setText(stripped_text)
1903
1909
  self.callsign.setCursorPosition(position)
1910
+ results = self.mscp.super_check(stripped_text)
1911
+ logger.debug(f"{results}")
1904
1912
 
1905
1913
  if " " in text:
1906
1914
  if stripped_text == "CW":
not1mm/bandmap.py CHANGED
@@ -19,12 +19,10 @@ import platform
19
19
  import sys
20
20
  import sqlite3
21
21
 
22
- from PyQt5 import QtCore, QtGui, Qt
22
+ from PyQt5 import QtCore, QtGui
23
23
  from PyQt5 import QtNetwork
24
24
  from PyQt5 import QtWidgets, uic
25
25
 
26
- from not1mm.lib.multicast import Multicast
27
-
28
26
  os.environ["QT_QPA_PLATFORMTHEME"] = "gnome"
29
27
 
30
28
  PIXELSPERSTEP = 10
@@ -259,6 +257,10 @@ class MainWindow(QtWidgets.QMainWindow):
259
257
  self.udpsocket.readyRead.connect(self.watch_udp)
260
258
  self.request_workedlist()
261
259
 
260
+ def quit_app(self):
261
+ """doc"""
262
+ app.quit()
263
+
262
264
  def connect(self):
263
265
  """doc"""
264
266
  if self.connected is True:
@@ -386,6 +388,12 @@ class MainWindow(QtWidgets.QMainWindow):
386
388
  ):
387
389
  self.worked_list = packet.get("worked", {})
388
390
  logger.debug("%s", f"{self.worked_list}")
391
+ continue
392
+ if (
393
+ packet.get("cmd", "") == "HALT"
394
+ and packet.get("station", "") == platform.node()
395
+ ):
396
+ self.quit_app()
389
397
 
390
398
  def spot_clicked(self):
391
399
  """dunno"""
not1mm/checkwindow.py ADDED
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Check Window
4
+ """
5
+ # pylint: disable=no-name-in-module, unused-import, no-member, invalid-name
6
+
7
+ import logging
8
+ import pkgutil
9
+ import platform
10
+ import queue
11
+ import os
12
+ import sys
13
+
14
+ from json import JSONDecodeError, loads, dumps
15
+ from pathlib import Path
16
+
17
+ from PyQt5 import uic
18
+ from PyQt5.QtCore import QDir, Qt
19
+ from PyQt5.QtWidgets import QApplication, QListWidget, QListWidgetItem, QMainWindow
20
+ from PyQt5 import QtNetwork
21
+ from PyQt5.QtGui import QFontDatabase
22
+
23
+ from not1mm.lib.database import DataBase
24
+ from not1mm.lib.multicast import Multicast
25
+ from not1mm.lib.super_check_partial import SCP
26
+
27
+ os.environ["QT_QPA_PLATFORMTHEME"] = "gnome"
28
+
29
+ loader = pkgutil.get_loader("not1mm")
30
+ WORKING_PATH = os.path.dirname(loader.get_filename())
31
+
32
+ if "XDG_DATA_HOME" in os.environ:
33
+ DATA_PATH = os.environ.get("XDG_DATA_HOME")
34
+ else:
35
+ DATA_PATH = str(Path.home() / ".local" / "share")
36
+ DATA_PATH += "/not1mm"
37
+
38
+ if "XDG_CONFIG_HOME" in os.environ:
39
+ CONFIG_PATH = os.environ.get("XDG_CONFIG_HOME")
40
+ else:
41
+ CONFIG_PATH = str(Path.home() / ".config")
42
+ CONFIG_PATH += "/not1mm"
43
+
44
+ MULTICAST_PORT = 2239
45
+ MULTICAST_GROUP = "239.1.1.1"
46
+ INTERFACE_IP = "0.0.0.0"
47
+
48
+
49
+ class MainWindow(QMainWindow):
50
+ """
51
+ The main window
52
+ """
53
+
54
+ dbname = None
55
+ pref = {}
56
+
57
+ def __init__(self, *args, **kwargs):
58
+ super().__init__(*args, **kwargs)
59
+ self.load_pref()
60
+ self.dbname = DATA_PATH + "/" + self.pref.get("current_database", "ham.db")
61
+ self.database = DataBase(self.dbname, WORKING_PATH)
62
+ self.database.current_contest = self.pref.get("contest", 0)
63
+ data_path = WORKING_PATH + "/data/checkwindow.ui"
64
+ uic.loadUi(data_path, self)
65
+ self.setWindowTitle("CheckWindow")
66
+ self.logList.clear()
67
+ self.masterList.clear()
68
+ self.telnetList.clear()
69
+ self.callhistoryList.clear()
70
+ # self.logList.hide()
71
+ self.telnetList.hide()
72
+ self.telnetListLabel.hide()
73
+ self.callhistoryList.hide()
74
+ self.callhistoryListLabel.hide()
75
+ self.mscp = SCP(WORKING_PATH)
76
+ self._udpwatch = None
77
+ self.udp_fifo = queue.Queue()
78
+ self.udpsocket = QtNetwork.QUdpSocket(self)
79
+ self.udpsocket.bind(
80
+ QtNetwork.QHostAddress.AnyIPv4,
81
+ MULTICAST_PORT,
82
+ QtNetwork.QUdpSocket.ShareAddress,
83
+ )
84
+ self.udpsocket.joinMulticastGroup(QtNetwork.QHostAddress(MULTICAST_GROUP))
85
+ self.udpsocket.readyRead.connect(self.watch_udp)
86
+
87
+ def quit_app(self):
88
+ """doc"""
89
+ app.quit()
90
+
91
+ def load_pref(self):
92
+ """Load preference file to get current db filename."""
93
+ try:
94
+ if os.path.exists(CONFIG_PATH + "/not1mm.json"):
95
+ with open(
96
+ CONFIG_PATH + "/not1mm.json", "rt", encoding="utf-8"
97
+ ) as file_descriptor:
98
+ self.pref = loads(file_descriptor.read())
99
+ logger.info("%s", self.pref)
100
+ else:
101
+ self.pref["current_database"] = "ham.db"
102
+
103
+ except IOError as exception:
104
+ logger.critical("Error: %s", exception)
105
+
106
+ def watch_udp(self):
107
+ """Puts UDP datagrams in a FIFO queue"""
108
+ while self.udpsocket.hasPendingDatagrams():
109
+ datagram, _, _ = self.udpsocket.readDatagram(
110
+ self.udpsocket.pendingDatagramSize()
111
+ )
112
+
113
+ try:
114
+ debug_info = f"{datagram.decode()}"
115
+ logger.debug(debug_info)
116
+ json_data = loads(datagram.decode())
117
+ except UnicodeDecodeError as err:
118
+ the_error = f"Not Unicode: {err}\n{datagram}"
119
+ logger.debug(the_error)
120
+ continue
121
+ except JSONDecodeError as err:
122
+ the_error = f"Not JSON: {err}\n{datagram}"
123
+ logger.debug(the_error)
124
+ continue
125
+ if json_data.get("station", "") != platform.node():
126
+ continue
127
+ if json_data.get("cmd", "") == "UPDATELOG":
128
+ self.clear_lists()
129
+ if json_data.get("cmd", "") == "CALLCHANGED":
130
+ call = json_data.get("call", "")
131
+ self.master_list(call)
132
+ self.log_list(call)
133
+ if json_data.get("cmd", "") == "NEWDB":
134
+ ...
135
+ # self.load_new_db()
136
+ if json_data.get("cmd", "") == "HALT":
137
+ self.quit_app()
138
+
139
+ def clear_lists(self) -> None:
140
+ """Clear match lists"""
141
+ self.logList.clear()
142
+ self.masterList.clear()
143
+ self.telnetList.clear()
144
+ self.callhistoryList.clear()
145
+
146
+ def master_list(self, call: str) -> None:
147
+ """Get MASTER.SCP matches to call"""
148
+ results = self.mscp.super_check(call)
149
+ self.masterList.clear()
150
+ for item in results:
151
+ listItem = QListWidgetItem(item)
152
+ self.masterList.addItem(listItem)
153
+ self.masterList.show()
154
+
155
+ def log_list(self, call: str) -> None:
156
+ """Parse calls in log for matches"""
157
+ self.logList.clear()
158
+ if call:
159
+ result = self.database.get_like_calls_and_bands(call)
160
+ for calls in result:
161
+ listItem = QListWidgetItem(calls)
162
+ self.logList.addItem(listItem)
163
+ self.logList.show()
164
+
165
+
166
+ def load_fonts_from_dir(directory: str) -> set:
167
+ """
168
+ Well it loads fonts from a directory...
169
+ """
170
+ font_families = set()
171
+ for _fi in QDir(directory).entryInfoList(["*.ttf", "*.woff", "*.woff2"]):
172
+ _id = QFontDatabase.addApplicationFont(_fi.absoluteFilePath())
173
+ font_families |= set(QFontDatabase.applicationFontFamilies(_id))
174
+ return font_families
175
+
176
+
177
+ def main():
178
+ """main entry"""
179
+ sys.exit(app.exec())
180
+
181
+
182
+ logger = logging.getLogger("__main__")
183
+ handler = logging.StreamHandler()
184
+ formatter = logging.Formatter(
185
+ datefmt="%H:%M:%S",
186
+ fmt="[%(asctime)s] %(levelname)s %(module)s - %(funcName)s Line %(lineno)d:\n%(message)s",
187
+ )
188
+ handler.setFormatter(formatter)
189
+ logger.addHandler(handler)
190
+
191
+ if Path("./debug").exists():
192
+ logger.setLevel(logging.DEBUG)
193
+ logger.debug("debugging on")
194
+ else:
195
+ logger.setLevel(logging.WARNING)
196
+ logger.warning("debugging off")
197
+
198
+ app = QApplication(sys.argv)
199
+ app.setStyle("Adwaita-Dark")
200
+ font_path = WORKING_PATH + "/data"
201
+ _families = load_fonts_from_dir(os.fspath(font_path))
202
+ window = MainWindow()
203
+ window.show()
204
+
205
+ if __name__ == "__main__":
206
+ main()
@@ -0,0 +1,103 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>MainWindow</class>
4
+ <widget class="QMainWindow" name="MainWindow">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>310</width>
10
+ <height>600</height>
11
+ </rect>
12
+ </property>
13
+ <property name="font">
14
+ <font>
15
+ <family>JetBrains Mono</family>
16
+ <pointsize>14</pointsize>
17
+ </font>
18
+ </property>
19
+ <property name="windowTitle">
20
+ <string>CheckWindow</string>
21
+ </property>
22
+ <widget class="QWidget" name="centralwidget">
23
+ <layout class="QGridLayout" name="gridLayout">
24
+ <item row="1" column="1">
25
+ <widget class="QListWidget" name="masterList"/>
26
+ </item>
27
+ <item row="1" column="3">
28
+ <widget class="QListWidget" name="callhistoryList"/>
29
+ </item>
30
+ <item row="1" column="2">
31
+ <widget class="QListWidget" name="telnetList"/>
32
+ </item>
33
+ <item row="1" column="0">
34
+ <widget class="QListWidget" name="logList"/>
35
+ </item>
36
+ <item row="0" column="0">
37
+ <widget class="QLabel" name="logListLabel">
38
+ <property name="font">
39
+ <font>
40
+ <family>JetBrains Mono</family>
41
+ <pointsize>10</pointsize>
42
+ </font>
43
+ </property>
44
+ <property name="text">
45
+ <string>Log</string>
46
+ </property>
47
+ </widget>
48
+ </item>
49
+ <item row="0" column="1">
50
+ <widget class="QLabel" name="masterListLabel">
51
+ <property name="font">
52
+ <font>
53
+ <family>JetBrains Mono</family>
54
+ <pointsize>10</pointsize>
55
+ </font>
56
+ </property>
57
+ <property name="text">
58
+ <string>Master</string>
59
+ </property>
60
+ </widget>
61
+ </item>
62
+ <item row="0" column="2">
63
+ <widget class="QLabel" name="telnetListLabel">
64
+ <property name="font">
65
+ <font>
66
+ <family>JetBrains Mono</family>
67
+ <pointsize>10</pointsize>
68
+ </font>
69
+ </property>
70
+ <property name="text">
71
+ <string>Telnet</string>
72
+ </property>
73
+ </widget>
74
+ </item>
75
+ <item row="0" column="3">
76
+ <widget class="QLabel" name="callhistoryListLabel">
77
+ <property name="font">
78
+ <font>
79
+ <family>JetBrains Mono</family>
80
+ <pointsize>10</pointsize>
81
+ </font>
82
+ </property>
83
+ <property name="text">
84
+ <string>Call</string>
85
+ </property>
86
+ </widget>
87
+ </item>
88
+ </layout>
89
+ </widget>
90
+ <widget class="QMenuBar" name="menubar">
91
+ <property name="geometry">
92
+ <rect>
93
+ <x>0</x>
94
+ <y>0</y>
95
+ <width>310</width>
96
+ <height>36</height>
97
+ </rect>
98
+ </property>
99
+ </widget>
100
+ </widget>
101
+ <resources/>
102
+ <connections/>
103
+ </ui>
not1mm/data/main.ui CHANGED
@@ -1082,6 +1082,7 @@
1082
1082
  </property>
1083
1083
  <addaction name="actionLog_Window"/>
1084
1084
  <addaction name="actionBandmap"/>
1085
+ <addaction name="actionCheck_Window"/>
1085
1086
  </widget>
1086
1087
  <widget class="QMenu" name="menuOther">
1087
1088
  <property name="title">
@@ -1481,6 +1482,11 @@
1481
1482
  <string>Update CTY</string>
1482
1483
  </property>
1483
1484
  </action>
1485
+ <action name="actionCheck_Window">
1486
+ <property name="text">
1487
+ <string>Check Window</string>
1488
+ </property>
1489
+ </action>
1484
1490
  </widget>
1485
1491
  <resources/>
1486
1492
  <connections/>
not1mm/lib/database.py CHANGED
@@ -920,6 +920,43 @@ class DataBase:
920
920
  logger.debug("%s", exception)
921
921
  return {}
922
922
 
923
+ def get_like_calls_and_bands(self, call: str) -> dict:
924
+ """
925
+ Returns a dict like:
926
+ {'K5TUX': [14.0, 21.0], 'N2CQR': [14.0], 'NE4RD': [14.0]}
927
+ """
928
+ try:
929
+ with sqlite3.connect(self.database) as conn:
930
+ conn.row_factory = self.row_factory
931
+ cursor = conn.cursor()
932
+ cursor.execute(
933
+ f"select call, band from DXLOG where call like '%{call}%' and ContestNR = {self.current_contest};"
934
+ )
935
+ result = cursor.fetchall()
936
+ worked_list = {}
937
+ # This converts a list of dicts like:
938
+ # [
939
+ # {"Call": "K5TUX", "Band": 14.0},
940
+ # {"Call": "K5TUX", "Band": 21.0},
941
+ # {"Call": "N2CQR", "Band": 14.0},
942
+ # {"Call": "NE4RD", "Band": 14.0},
943
+ # ]
944
+ #
945
+ # To:
946
+ # {'K5TUX': [14.0, 21.0], 'N2CQR': [14.0], 'NE4RD': [14.0]}
947
+ for worked_dict in result:
948
+ call = worked_dict.get("Call")
949
+ if call in worked_list:
950
+ bandlist = worked_list[call]
951
+ bandlist.append(worked_dict["Band"])
952
+ worked_list[call] = bandlist
953
+ continue
954
+ worked_list[call] = [worked_dict["Band"]]
955
+ return worked_list
956
+ except sqlite3.OperationalError as exception:
957
+ logger.debug("%s", exception)
958
+ return {}
959
+
923
960
  def get_unique_band_and_mode(self) -> dict:
924
961
  """get count of unique band and mode as {mult: x}"""
925
962
  try:
@@ -0,0 +1,56 @@
1
+ """Super Check Partial"""
2
+
3
+ import logging
4
+
5
+ import requests
6
+
7
+ MASTER_SCP_URL = "https://www.supercheckpartial.com/MASTER.SCP"
8
+
9
+ if __name__ == "__main__":
10
+ print("I'm not the program you are looking for.")
11
+
12
+ logger = logging.getLogger("__main__")
13
+
14
+
15
+ class SCP:
16
+ """Super check partial"""
17
+
18
+ def __init__(self, working_path):
19
+ """initialize dialog"""
20
+ self.scp = []
21
+ self.working_path = working_path
22
+ self.read_scp()
23
+
24
+ def update_masterscp(self) -> None:
25
+ """Update the MASTER.SCP file.
26
+ - Returns True if successful
27
+ - Otherwise False
28
+ """
29
+ with requests.Session() as session:
30
+ the_request = session.get(MASTER_SCP_URL)
31
+ if the_request.status_code == 200:
32
+ with open(self.working_path + "/data/MASTER.SCP", "wb+") as file:
33
+ file.write(the_request.content)
34
+ return True
35
+ return False
36
+
37
+ def read_scp(self):
38
+ """
39
+ Reads in a list of known contesters into an internal dictionary
40
+ """
41
+ try:
42
+ with open(
43
+ self.working_path + "/data/MASTER.SCP", "r", encoding="utf-8"
44
+ ) as file_descriptor:
45
+ self.scp = file_descriptor.readlines()
46
+ self.scp = list(map(lambda x: x.strip(), self.scp))
47
+ except IOError as exception:
48
+ logger.critical("read_scp: read error: %s", exception)
49
+
50
+ def super_check(self, acall: str) -> list:
51
+ """
52
+ Performs a supercheck partial on the callsign entered in the field.
53
+ """
54
+ if len(acall) > 2:
55
+ return list(filter(lambda x: x.startswith(acall), self.scp))
56
+ return []
not1mm/lib/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  """It's the version"""
2
- __version__ = "23.7.29"
2
+ __version__ = "23.8.6"
not1mm/logwindow.py CHANGED
@@ -11,10 +11,7 @@ import os
11
11
  import pkgutil
12
12
  import platform
13
13
  import queue
14
- import socket
15
14
  import sys
16
- import time
17
- import threading
18
15
 
19
16
  from json import JSONDecodeError, loads, dumps
20
17
  from pathlib import Path
@@ -164,6 +161,10 @@ class MainWindow(QtWidgets.QMainWindow):
164
161
  packet, QtNetwork.QHostAddress(MULTICAST_GROUP), MULTICAST_PORT
165
162
  )
166
163
 
164
+ def quit_app(self):
165
+ """doc"""
166
+ app.quit()
167
+
167
168
  def get_column(self, name: str) -> int:
168
169
  """returns the column number of the given column name."""
169
170
  for key, value in self.columns.items():
@@ -625,6 +626,8 @@ class MainWindow(QtWidgets.QMainWindow):
625
626
  for column in columns_to_show:
626
627
  self.generalLog.setColumnHidden(self.get_column(column), False)
627
628
  self.focusedLog.setColumnHidden(self.get_column(column), False)
629
+ if json_data.get("cmd", "") == "HALT":
630
+ self.quit_app()
628
631
 
629
632
  def show_like_calls(self, call):
630
633
  """Show like calls"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: not1mm
3
- Version: 23.7.29
3
+ Version: 23.8.6
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
@@ -24,7 +24,7 @@ Requires-Dist: psutil
24
24
  Requires-Dist: sounddevice
25
25
  Requires-Dist: soundfile
26
26
  Requires-Dist: numpy
27
- Requires-Dist: notctyparser (>=23.6.21)
27
+ Requires-Dist: notctyparser >=23.6.21
28
28
 
29
29
  # Not1MM
30
30
 
@@ -89,6 +89,7 @@ Requires-Dist: notctyparser (>=23.6.21)
89
89
  - [Editing a contact](#editing-a-contact)
90
90
  - [Recalulate Mults](#recalulate-mults)
91
91
  - [Bandmap](#bandmap)
92
+ - [Check Window](#check-window)
92
93
  - [Cabrillo](#cabrillo)
93
94
  - [ADIF](#adif)
94
95
  - [Dupe checking](#dupe-checking)
@@ -150,13 +151,8 @@ I wish to thank those who've contributed to the project.
150
151
 
151
152
  ## Recent Changes
152
153
 
153
- - [23-7-29] Add YOUTH and YL overlay categories.
154
- - [23-7-28] Added NAQP SSB and CW. Added optional move to next field with spacebar.
155
- - [23-7-27] Check if bandwidth returned is not a number.
156
- - [23-7-13] Add IARU HF contest.
157
- - [23-7-11] Add mode to logwindow. Highlight already worked calls in bandmap. Add FM and AM to Field Day, since I guess it's still a thing.
158
- - [23-7-5] Fix coredump in bandmap after CTRL-G.
159
- - [23-7-2] bandmap now requests worked list at startup. Completed ARRL Field Day plugin.
154
+ - [23-8-6] Add parsing of local log to check window.
155
+ - [23-8-5] Add Check Window. Moved MASTER.SCP stuff to it's own class. Close sub windows when main app closes.
160
156
 
161
157
  See [CHANGELOG.md](CHANGELOG.md) for prior changes.
162
158
 
@@ -483,6 +479,14 @@ VFO indicator now displays as small triangle in the frequency tickmarks. A small
483
479
 
484
480
  Clicked on spots now tune the radio and set the callsign field. Previously worked calls are displayed in red.
485
481
 
482
+ ## Check Window
483
+
484
+ `Window`>`Check Window`
485
+
486
+ As you enter a callsign, the Check Window will show probable matches to calls either in the MASTER.SCP file, or your local log. The MASTER.SCP column will show results for strings of 3 or more matching from the start of the call string. The local log column will show matches of any length appearing anywhere in the string.
487
+
488
+ ![Check Window](https://github.com/mbridak/not1mm/raw/master/pic/checkwindow.png)
489
+
486
490
  ## Cabrillo
487
491
 
488
492
  Click on `File` > `Generate Cabrillo`
@@ -1,13 +1,15 @@
1
1
  not1mm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- not1mm/__main__.py,sha256=JZqEGoGeOWe_Qc3tmgd5MtZkwC6qUfz1_D2ADVsK7DY,96330
3
- not1mm/bandmap.py,sha256=2p8Iw2_ZPl5ttAvR6ZBdkahP4wgIN0GauWfCcmMCjzA,26668
4
- not1mm/logwindow.py,sha256=Liz1ltFp6ZL9bzGAah1FbgcNAdKwI6nYCqiMdb-_IjA,34229
2
+ not1mm/__main__.py,sha256=epgycpDTK2ELV0NNwQcoukeC7sJVSdSkoD4pSurn5d0,96702
3
+ not1mm/bandmap.py,sha256=5mANS6F9c11CrEzHD5EL2sTYB_d-ncvRofrLg8bHMP0,26884
4
+ not1mm/checkwindow.py,sha256=gJYc67pMKbxNQMPGJ1PI41nKWGXvG1_H1n9gQRvXsJA,6451
5
+ not1mm/logwindow.py,sha256=DOv2L3wEWzxrIFb5mAg6yaIoW9ejSbcuLN6D5HiLgf8,34331
5
6
  not1mm/data/JetBrainsMono-Regular.ttf,sha256=UOHctAKY_PzCGh7zy-6f6egnCcSK0wzmF0csBqO9lDY,203952
6
7
  not1mm/data/MASTER.SCP,sha256=J7Xi62-SF0vO8X1IvQE5O-dESikT6OVmrT_x80F7f4Y,657382
7
8
  not1mm/data/about.ui,sha256=7TqvtXFFm0Rmcu0bmLupwpO1CsK8MekfZ09_xn6kZrQ,2067
8
9
  not1mm/data/alpha bravo charlie delta.txt,sha256=d5QMmSWEUAe4Rj1XbNjTPLa_5Be4Se6u5LUIqAYidOQ,224
9
10
  not1mm/data/bandmap.ui,sha256=FB2NaxSK-ZZvfYHU9Mu8FkQxTeVHcFGV40zIqgBXAFo,5246
10
11
  not1mm/data/check.png,sha256=UvFOLr8V-79qnjW8wUaGItXk_OSP8m8hqPevs8NDlFY,387
12
+ not1mm/data/checkwindow.ui,sha256=nc4FRc4D3ozC1jhm96Q2y6rolayKF6OwMrbCSaQ-vbg,2572
11
13
  not1mm/data/configuration.ui,sha256=-6LKpkTWFuWy9gVBeQ5k3fg5Mw01rwAxp6fQag0E38c,41522
12
14
  not1mm/data/contests.sql,sha256=4hmJCDvrbxnA_Y5S4T5o52TZieeFk6QUwFerwlFePNA,89307
13
15
  not1mm/data/cty.json,sha256=0l3wUE5vsc9yknd59ffRLFtAPcnXNl2IaKAmQojGBGI,4667346
@@ -21,7 +23,7 @@ not1mm/data/k6gte.not1mm-128.png,sha256=vWqt3Cgsaguj-BBiIoSJApzzhisPxldM8HZQbZ05
21
23
  not1mm/data/k6gte.not1mm-32.png,sha256=yucSwzlmqv3NegdWUvPvZzSgP7G22Ky3se8TWRXvzfI,1108
22
24
  not1mm/data/k6gte.not1mm-64.png,sha256=1KQvk0WBckUds79BvIFUt-KdTwQKKvTz6hiJu8MiT68,2152
23
25
  not1mm/data/logwindow.ui,sha256=_-wobHhIjALzCswyXIrqNadnLdc88eay1GNF23a-Qh0,970
24
- not1mm/data/main.ui,sha256=Tulm6Wy79P5vWe5EtfpH0MX4yXMAKogxwJWWuZqZN8g,44985
26
+ not1mm/data/main.ui,sha256=JLoTY7pl9GpxiZB-YirfPa7GSp5CzeIB4WV0LjEoTmw,45152
25
27
  not1mm/data/new_contest.ui,sha256=9ujIv7Q5DRIhT77QKQE7Kddx3a7WiMFe4Dvy2UUDK6M,18584
26
28
  not1mm/data/not1mm.html,sha256=Z52qcafOQJrgD_bbgy86C-PU-tb4kGlWv9gSxRXAZ1A,20129
27
29
  not1mm/data/opon.ui,sha256=6r9_6ORGfNqwOnpzQjaJ1tWP_81amuXqLYlx1hHgdME,2018
@@ -81,7 +83,7 @@ not1mm/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
83
  not1mm/lib/about.py,sha256=O9i8ypv2W9KZkPAp2bcRI0J5RgPE5R1vMfU8ZGlok_E,379
82
84
  not1mm/lib/cat_interface.py,sha256=eKsxC42Mm9wv7E2YQmgL7tLA2Gom-vCVaHHRf2Kitdk,15676
83
85
  not1mm/lib/cwinterface.py,sha256=fZ5BXVyF7by0yGTJVznUTjRCxRt3lJaUIsNC-_mCGP4,3123
84
- not1mm/lib/database.py,sha256=wE95yuMKZDOS_QVxyItzrV8WxAoFwS-zV309r2ojx0w,38549
86
+ not1mm/lib/database.py,sha256=j_AHxc_cW8vyfwmNrqO9DUPW2HnJqtMKKQeqq233A64,40117
85
87
  not1mm/lib/edit_contact.py,sha256=YwuX-BuIa7AuPtLRENs4jTzxOrtk6MCxZj3BR_bDPW8,357
86
88
  not1mm/lib/edit_macro.py,sha256=lyToZb1nmcONNFh6W35NzYHLU48gbAs2_OsnuRQGHck,559
87
89
  not1mm/lib/edit_opon.py,sha256=GqAOJMiC265_4YRVbkT1PflBuCa4HiCNfRhq8-J6ZVY,363
@@ -93,7 +95,8 @@ not1mm/lib/n1mm.py,sha256=O3U2dhOX-_5nBomyuiyfx-_GQk6rj067lwrcC9GtDpQ,5713
93
95
  not1mm/lib/new_contest.py,sha256=mHKNCS3iKOKN-bT9d8ZK3JemThOZFQ0ikfUSS0-ZTpY,354
94
96
  not1mm/lib/select_contest.py,sha256=XQdRUkPAIHIMVsilm82M54b_v9yWpYrZ1nfInJrtZoo,363
95
97
  not1mm/lib/settings.py,sha256=tkCWgJ3CpNkGR_IyCTOCIlO6PEPZCShHO9FL-9Wono8,6885
96
- not1mm/lib/version.py,sha256=PG7XpmtnDw8gsY6Joi9Ivm4z4i8gn_nG8xPiLXyAYTQ,47
98
+ not1mm/lib/super_check_partial.py,sha256=GlXgtIblL602iW-V6Mmdf5S4FxtzJ95TbPMMa9xXUfg,1692
99
+ not1mm/lib/version.py,sha256=hATNe5bxbwO_Se-Zg1fJdhcw2L9NT4hAiGokiArFTD4,46
97
100
  not1mm/lib/versiontest.py,sha256=8vDNptuBBunn-1IGkjNaquehqBYUJyjrPSF8Igmd4_Y,1286
98
101
  not1mm/plugins/10_10_fall_cw.py,sha256=uV66Mmj6vuNGgY_4PX4lKWvvkyqBQNDf8gAAGTIoKxE,13883
99
102
  not1mm/plugins/10_10_spring_cw.py,sha256=yAxvP1fR5vg4cqpADvG0BN-ibjW7lSAcn-p9VzXNW3g,13888
@@ -125,9 +128,9 @@ not1mm/testing/multicast_listener.py,sha256=2CkiyZ4EQxBX68_1QzGIX9g_UB9-CQq63OH-
125
128
  not1mm/testing/n1mm_listener.py,sha256=UD-qyKEnppQua330WEFKMvMJaNjnYKi7dDuX_RGB5lQ,1099
126
129
  not1mm/testing/test.py,sha256=wGblvMlyOCVkEiHbxE6wvLsorim15ehL72_EZLQeWkk,1660
127
130
  testing/test.py,sha256=icT6vZPbJaZWJbEZ09nSbPmTFeiaL7LbXqM_sjhDisI,471
128
- not1mm-23.7.29.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
129
- not1mm-23.7.29.dist-info/METADATA,sha256=Ai8RDzAB3cQeExSXvLPyCAqoVMNkfZJSfkvt-G_A3As,23794
130
- not1mm-23.7.29.dist-info/WHEEL,sha256=AtBG6SXL3KF_v0NxLf0ehyVOh0cold-JbJYXNGorC6Q,92
131
- not1mm-23.7.29.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
132
- not1mm-23.7.29.dist-info/top_level.txt,sha256=-NwUrh4k1kzpOvf720xYWSTKSlr-zNSIz3D_eplrxLs,15
133
- not1mm-23.7.29.dist-info/RECORD,,
131
+ not1mm-23.8.6.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
132
+ not1mm-23.8.6.dist-info/METADATA,sha256=nvBHO-Wu4EX-eMTfuwrP4zuRJaqT7aOsIPqWXlT5xPM,23938
133
+ not1mm-23.8.6.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92
134
+ not1mm-23.8.6.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
135
+ not1mm-23.8.6.dist-info/top_level.txt,sha256=-NwUrh4k1kzpOvf720xYWSTKSlr-zNSIz3D_eplrxLs,15
136
+ not1mm-23.8.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.0)
2
+ Generator: bdist_wheel (0.41.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5