not1mm 24.3.19__py3-none-any.whl → 24.3.21__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 (66) hide show
  1. not1mm/__main__.py +289 -123
  2. not1mm/bandmap.py +168 -163
  3. not1mm/checkwindow.py +55 -107
  4. not1mm/data/MASTER.SCP +1077 -749
  5. not1mm/data/bandmap.ui +4 -4
  6. not1mm/data/checkwindow.ui +9 -16
  7. not1mm/data/logwindow.ui +16 -11
  8. not1mm/data/main.ui +16 -6
  9. not1mm/data/vfo.ui +64 -52
  10. not1mm/data/vfo2.ui +84 -0
  11. not1mm/fsutils.py +38 -0
  12. not1mm/lib/about.py +4 -2
  13. not1mm/lib/cat_interface.py +1 -1
  14. not1mm/lib/cwinterface.py +1 -1
  15. not1mm/lib/database.py +4 -4
  16. not1mm/lib/edit_contact.py +2 -2
  17. not1mm/lib/edit_macro.py +2 -3
  18. not1mm/lib/edit_opon.py +2 -2
  19. not1mm/lib/edit_station.py +3 -3
  20. not1mm/lib/ham_utility.py +1 -1
  21. not1mm/lib/lookup.py +1 -1
  22. not1mm/lib/multicast.py +9 -4
  23. not1mm/lib/n1mm.py +1 -1
  24. not1mm/lib/new_contest.py +2 -2
  25. not1mm/lib/select_contest.py +2 -2
  26. not1mm/lib/settings.py +3 -4
  27. not1mm/lib/super_check_partial.py +6 -5
  28. not1mm/lib/version.py +1 -1
  29. not1mm/logwindow.py +60 -104
  30. not1mm/plugins/10_10_fall_cw.py +1 -1
  31. not1mm/plugins/10_10_spring_cw.py +1 -1
  32. not1mm/plugins/10_10_summer_phone.py +1 -1
  33. not1mm/plugins/10_10_winter_phone.py +1 -1
  34. not1mm/plugins/arrl_10m.py +1 -1
  35. not1mm/plugins/arrl_dx_cw.py +1 -1
  36. not1mm/plugins/arrl_dx_ssb.py +1 -1
  37. not1mm/plugins/arrl_field_day.py +1 -1
  38. not1mm/plugins/arrl_ss_cw.py +1 -1
  39. not1mm/plugins/arrl_ss_phone.py +1 -1
  40. not1mm/plugins/arrl_vhf_jan.py +1 -1
  41. not1mm/plugins/arrl_vhf_jun.py +1 -1
  42. not1mm/plugins/arrl_vhf_sep.py +1 -1
  43. not1mm/plugins/canada_day.py +1 -1
  44. not1mm/plugins/cq_160_cw.py +1 -1
  45. not1mm/plugins/cq_160_ssb.py +1 -1
  46. not1mm/plugins/cq_wpx_cw.py +1 -1
  47. not1mm/plugins/cq_wpx_ssb.py +1 -1
  48. not1mm/plugins/cq_ww_cw.py +1 -1
  49. not1mm/plugins/cq_ww_ssb.py +1 -1
  50. not1mm/plugins/cwt.py +1 -1
  51. not1mm/plugins/general_logging.py +1 -1
  52. not1mm/plugins/iaru_hf.py +1 -1
  53. not1mm/plugins/jidx_cw.py +1 -1
  54. not1mm/plugins/jidx_ph.py +1 -1
  55. not1mm/plugins/naqp_cw.py +1 -1
  56. not1mm/plugins/naqp_ssb.py +1 -1
  57. not1mm/plugins/phone_weekly_test.py +1 -1
  58. not1mm/plugins/stew_perry_topband.py +1 -1
  59. not1mm/plugins/winter_field_day.py +1 -1
  60. not1mm/vfo.py +77 -98
  61. {not1mm-24.3.19.dist-info → not1mm-24.3.21.dist-info}/METADATA +3 -1
  62. {not1mm-24.3.19.dist-info → not1mm-24.3.21.dist-info}/RECORD +66 -64
  63. {not1mm-24.3.19.dist-info → not1mm-24.3.21.dist-info}/LICENSE +0 -0
  64. {not1mm-24.3.19.dist-info → not1mm-24.3.21.dist-info}/WHEEL +0 -0
  65. {not1mm-24.3.19.dist-info → not1mm-24.3.21.dist-info}/entry_points.txt +0 -0
  66. {not1mm-24.3.19.dist-info → not1mm-24.3.21.dist-info}/top_level.txt +0 -0
not1mm/__main__.py CHANGED
@@ -3,7 +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
+ # pylint: disable=logging-fstring-interpolation, logging-not-lazy, line-too-long
7
7
 
8
8
  # alt cluster hamqth.com 7300
9
9
 
@@ -11,12 +11,14 @@ import datetime
11
11
  import importlib
12
12
  import locale
13
13
  import logging
14
+ from logging.handlers import RotatingFileHandler
14
15
  import os
15
16
 
16
17
  import platform
17
18
  import re
18
19
  import socket
19
- import subprocess
20
+
21
+ # import subprocess
20
22
  import sys
21
23
  import threading
22
24
  import uuid
@@ -32,7 +34,7 @@ import soundfile as sf
32
34
  from PyQt5 import QtCore, QtGui, QtWidgets, uic
33
35
  from PyQt5.QtCore import QDir, Qt
34
36
  from PyQt5.QtGui import QFontDatabase
35
- from PyQt5.QtWidgets import QFileDialog
37
+ from PyQt5.QtWidgets import QFileDialog, QDockWidget
36
38
 
37
39
  from not1mm.lib.about import About
38
40
  from not1mm.lib.cat_interface import CAT
@@ -62,31 +64,15 @@ from not1mm.lib.settings import Settings
62
64
  from not1mm.lib.version import __version__
63
65
  from not1mm.lib.versiontest import VersionTest
64
66
 
65
- # DeprecationWarning: 'pkgutil.get_loader' is deprecated and slated for removal in Python 3.14
66
- # loader = pkgutil.get_loader("not1mm")
67
- # WORKING_PATH = os.path.dirname(loader.get_filename())
68
- WORKING_PATH = os.path.dirname(__loader__.get_filename())
69
-
70
- DATA_PATH = os.environ.get("XDG_DATA_HOME", str(Path.home() / ".local" / "share"))
71
- DATA_PATH += "/not1mm"
72
-
73
- try:
74
- os.mkdir(DATA_PATH)
75
- except FileExistsError:
76
- ...
77
-
78
- CONFIG_PATH = os.environ.get("XDG_CONFIG_HOME", str(Path.home() / ".config"))
79
- CONFIG_PATH += "/not1mm"
80
-
81
- try:
82
- os.mkdir(CONFIG_PATH)
83
- except FileExistsError:
84
- ...
85
-
67
+ import not1mm.fsutils as fsutils
68
+ from not1mm.logwindow import LogWindow
69
+ from not1mm.checkwindow import CheckWindow
70
+ from not1mm.bandmap import BandMapWindow
71
+ from not1mm.vfo import VfoWindow
86
72
 
87
73
  CTYFILE = {}
88
74
 
89
- with open(WORKING_PATH + "/data/cty.json", "rt", encoding="utf-8") as c_file:
75
+ with open(fsutils.APP_DATA_PATH / "cty.json", "rt", encoding="utf-8") as c_file:
90
76
  CTYFILE = loads(c_file.read())
91
77
 
92
78
  poll_time = datetime.datetime.now()
@@ -137,7 +123,7 @@ class MainWindow(QtWidgets.QMainWindow):
137
123
  "contest": "",
138
124
  "multicast_group": "239.1.1.1",
139
125
  "multicast_port": 2239,
140
- "interface_ip": "0.0.0.0",
126
+ "interface_ip": "127.0.0.1",
141
127
  "send_n1mm_packets": False,
142
128
  "n1mm_station_name": "20M CW Tent",
143
129
  "n1mm_operator": "Bernie",
@@ -184,24 +170,33 @@ class MainWindow(QtWidgets.QMainWindow):
184
170
  contest_dialog = None
185
171
  configuration_dialog = None
186
172
  opon_dialog = None
187
- dbname = DATA_PATH + "/ham.db"
173
+ dbname = fsutils.USER_DATA_PATH, "/ham.db"
188
174
  radio_state = {}
189
175
  rig_control = None
190
176
  worked_list = {}
191
177
  cw_entry_visible = False
192
178
  last_focus = None
193
179
  oldtext = ""
180
+ text_color = Qt.black
181
+ current_palette = None
182
+
183
+ log_window = None
184
+ check_window = None
185
+ bandmap_window = None
186
+ vfo_window = None
194
187
 
195
188
  def __init__(self, *args, **kwargs):
196
189
  super().__init__(*args, **kwargs)
197
190
  logger.info("MainWindow: __init__")
198
- data_path = WORKING_PATH + "/data/main.ui"
191
+ self.setCorner(Qt.TopRightCorner, Qt.RightDockWidgetArea)
192
+ self.setCorner(Qt.BottomRightCorner, Qt.RightDockWidgetArea)
193
+ data_path = fsutils.APP_DATA_PATH / "main.ui"
199
194
  uic.loadUi(data_path, self)
200
195
  self.cw_entry.hide()
201
196
  self.leftdot.hide()
202
197
  self.rightdot.hide()
203
198
  self.n1mm = N1MM()
204
- self.mscp = SCP(WORKING_PATH)
199
+ self.mscp = SCP(fsutils.APP_DATA_PATH)
205
200
  self.next_field = self.other_2
206
201
  self.dupe_indicator.hide()
207
202
  self.cw_speed.valueChanged.connect(self.cwspeed_spinbox_changed)
@@ -210,6 +205,7 @@ class MainWindow(QtWidgets.QMainWindow):
210
205
  self.cw_entry.returnPressed.connect(self.toggle_cw_entry)
211
206
 
212
207
  self.actionCW_Macros.triggered.connect(self.cw_macros_state_changed)
208
+ self.actionDark_Mode_2.triggered.connect(self.dark_mode_state_changed)
213
209
  self.actionCommand_Buttons.triggered.connect(self.command_buttons_state_change)
214
210
  self.actionLog_Window.triggered.connect(self.launch_log_window)
215
211
  self.actionBandmap.triggered.connect(self.launch_bandmap_window)
@@ -255,15 +251,15 @@ class MainWindow(QtWidgets.QMainWindow):
255
251
 
256
252
  self.sent.setText("59")
257
253
  self.receive.setText("59")
258
- icon_path = WORKING_PATH + "/data/"
259
- self.greendot = QtGui.QPixmap(icon_path + "greendot.png")
260
- self.reddot = QtGui.QPixmap(icon_path + "reddot.png")
254
+ icon_path = fsutils.APP_DATA_PATH
255
+ self.greendot = QtGui.QPixmap(str(icon_path / "greendot.png"))
256
+ self.reddot = QtGui.QPixmap(str(icon_path / "reddot.png"))
261
257
  self.leftdot.setPixmap(self.greendot)
262
258
  self.rightdot.setPixmap(self.reddot)
263
259
 
264
- self.radio_grey = QtGui.QPixmap(icon_path + "radio_grey.png")
265
- self.radio_red = QtGui.QPixmap(icon_path + "radio_red.png")
266
- self.radio_green = QtGui.QPixmap(icon_path + "radio_green.png")
260
+ self.radio_grey = QtGui.QPixmap(str(icon_path / "radio_grey.png"))
261
+ self.radio_red = QtGui.QPixmap(str(icon_path / "radio_red.png"))
262
+ self.radio_green = QtGui.QPixmap(str(icon_path / "radio_green.png"))
267
263
  self.radio_icon.setPixmap(self.radio_grey)
268
264
 
269
265
  self.F1.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
@@ -461,9 +457,14 @@ class MainWindow(QtWidgets.QMainWindow):
461
457
  "RTTY": self.band_indicators_rtty,
462
458
  }
463
459
 
460
+ self.setWindowIcon(
461
+ QtGui.QIcon(str(fsutils.APP_DATA_PATH / "k6gte.not1mm-64.png"))
462
+ )
464
463
  self.readpreferences()
465
- self.dbname = DATA_PATH + "/" + self.pref.get("current_database", "ham.db")
466
- self.database = DataBase(self.dbname, WORKING_PATH)
464
+ self.dbname = fsutils.USER_DATA_PATH / self.pref.get(
465
+ "current_database", "ham.db"
466
+ )
467
+ self.database = DataBase(self.dbname, fsutils.APP_DATA_PATH)
467
468
  self.station = self.database.fetch_station()
468
469
  if self.station is None:
469
470
  self.station = {}
@@ -480,11 +481,80 @@ class MainWindow(QtWidgets.QMainWindow):
480
481
  if self.pref.get("contest"):
481
482
  self.load_contest()
482
483
 
483
- if VersionTest(__version__).test():
484
- self.show_message_box(
485
- "There is a newer version of not1mm available.\n"
486
- "You can udate to the current version by using:\npip install -U not1mm"
484
+ if not DEBUG_ENABLED:
485
+ if VersionTest(__version__).test():
486
+ self.show_message_box(
487
+ "There is a newer version of not1mm available.\n"
488
+ "You can udate to the current version by using:\npip install -U not1mm"
489
+ )
490
+
491
+ def setDarkMode(self, dark):
492
+ """testing"""
493
+
494
+ logger.debug(f"Dark mode set to: {dark}")
495
+
496
+ cmd = {}
497
+ cmd["cmd"] = "DARKMODE"
498
+ cmd["state"] = dark
499
+ cmd["station"] = platform.node()
500
+ self.multicast_interface.send_as_json(cmd)
501
+
502
+ if dark:
503
+ darkPalette = QtGui.QPalette()
504
+ darkColor = QtGui.QColor(45, 45, 45)
505
+
506
+ disabledColor = QtGui.QColor(127, 127, 127)
507
+ darkPalette.setColor(QtGui.QPalette.Window, darkColor)
508
+ darkPalette.setColor(QtGui.QPalette.WindowText, Qt.white)
509
+ darkPalette.setColor(QtGui.QPalette.Base, QtGui.QColor(18, 18, 18))
510
+ darkPalette.setColor(QtGui.QPalette.AlternateBase, darkColor)
511
+ darkPalette.setColor(QtGui.QPalette.Text, Qt.white)
512
+ darkPalette.setColor(
513
+ QtGui.QPalette.Disabled, QtGui.QPalette.Text, disabledColor
514
+ )
515
+ darkPalette.setColor(QtGui.QPalette.Button, darkColor)
516
+ darkPalette.setColor(QtGui.QPalette.ButtonText, Qt.white)
517
+ darkPalette.setColor(
518
+ QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, disabledColor
487
519
  )
520
+ darkPalette.setColor(QtGui.QPalette.BrightText, Qt.red)
521
+ darkPalette.setColor(QtGui.QPalette.Link, QtGui.QColor(42, 130, 218))
522
+ darkPalette.setColor(QtGui.QPalette.Highlight, QtGui.QColor(42, 130, 218))
523
+ darkPalette.setColor(QtGui.QPalette.HighlightedText, Qt.black)
524
+ darkPalette.setColor(
525
+ QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, disabledColor
526
+ )
527
+ self.current_palette = darkPalette
528
+ self.setPalette(darkPalette)
529
+ self.text_color = Qt.white
530
+ self.menuFile.setPalette(darkPalette)
531
+ self.menuHelp.setPalette(darkPalette)
532
+ self.menuOther.setPalette(darkPalette)
533
+ self.menuView.setPalette(darkPalette)
534
+ self.menuWindow.setPalette(darkPalette)
535
+ self.callsign.setPalette(darkPalette)
536
+ self.sent.setPalette(darkPalette)
537
+ self.receive.setPalette(darkPalette)
538
+ self.other_1.setPalette(darkPalette)
539
+ self.other_2.setPalette(darkPalette)
540
+ self.cw_entry.setPalette(darkPalette)
541
+
542
+ else:
543
+ palette = self.style().standardPalette()
544
+ self.current_palette = palette
545
+ self.setPalette(palette)
546
+ self.menuFile.setPalette(palette)
547
+ self.menuHelp.setPalette(palette)
548
+ self.menuOther.setPalette(palette)
549
+ self.menuView.setPalette(palette)
550
+ self.menuWindow.setPalette(palette)
551
+ self.callsign.setPalette(palette)
552
+ self.sent.setPalette(palette)
553
+ self.receive.setPalette(palette)
554
+ self.other_1.setPalette(palette)
555
+ self.other_2.setPalette(palette)
556
+ self.cw_entry.setPalette(palette)
557
+ self.text_color = Qt.black
488
558
 
489
559
  def set_radio_icon(self, state: int) -> None:
490
560
  """
@@ -624,6 +694,8 @@ class MainWindow(QtWidgets.QMainWindow):
624
694
  """
625
695
 
626
696
  message_box = QtWidgets.QMessageBox()
697
+ if self.current_palette:
698
+ message_box.setPalette(self.current_palette)
627
699
  message_box.setIcon(QtWidgets.QMessageBox.Information)
628
700
  message_box.setText(message)
629
701
  message_box.setWindowTitle("Information")
@@ -643,9 +715,12 @@ class MainWindow(QtWidgets.QMainWindow):
643
715
  None
644
716
  """
645
717
 
646
- self.about_dialog = About(WORKING_PATH)
718
+ self.about_dialog = About(fsutils.APP_DATA_PATH)
719
+ if self.current_palette:
720
+ self.about_dialog.setPalette(self.current_palette)
721
+
647
722
  self.about_dialog.donors.setSource(
648
- QtCore.QUrl.fromLocalFile(WORKING_PATH + "/data/donors.html")
723
+ QtCore.QUrl.fromLocalFile(f"{fsutils.APP_DATA_PATH / 'donors.html'}")
649
724
  )
650
725
  self.about_dialog.open()
651
726
 
@@ -662,11 +737,14 @@ class MainWindow(QtWidgets.QMainWindow):
662
737
  None
663
738
  """
664
739
 
665
- self.about_dialog = About(WORKING_PATH)
740
+ self.about_dialog = About(fsutils.APP_DATA_PATH)
741
+ if self.current_palette:
742
+ self.about_dialog.setPalette(self.current_palette)
743
+
666
744
  self.about_dialog.setWindowTitle("Help")
667
745
  self.about_dialog.setGeometry(0, 0, 800, 600)
668
746
  self.about_dialog.donors.setSource(
669
- QtCore.QUrl.fromLocalFile(WORKING_PATH + "/data/not1mm.html")
747
+ QtCore.QUrl.fromLocalFile(str(fsutils.APP_DATA_PATH / "not1mm.html"))
670
748
  )
671
749
  self.about_dialog.open()
672
750
 
@@ -703,7 +781,9 @@ class MainWindow(QtWidgets.QMainWindow):
703
781
  None
704
782
  """
705
783
 
706
- self.configuration_dialog = Settings(WORKING_PATH, CONFIG_PATH, self.pref)
784
+ self.configuration_dialog = Settings(fsutils.APP_DATA_PATH, self.pref)
785
+ if self.current_palette:
786
+ self.configuration_dialog.setPalette(self.current_palette)
707
787
  self.configuration_dialog.usehamdb_radioButton.hide()
708
788
  self.configuration_dialog.show()
709
789
  self.configuration_dialog.accepted.connect(self.edit_configuration_return)
@@ -723,7 +803,7 @@ class MainWindow(QtWidgets.QMainWindow):
723
803
 
724
804
  self.configuration_dialog.save_changes()
725
805
  self.write_preference()
726
- logger.debug("%s", f"{self.pref}")
806
+ # logger.debug("%s", f"{self.pref}")
727
807
  self.readpreferences()
728
808
 
729
809
  def new_database(self) -> None:
@@ -743,10 +823,12 @@ class MainWindow(QtWidgets.QMainWindow):
743
823
  if filename:
744
824
  if filename[-3:] != ".db":
745
825
  filename += ".db"
746
- self.pref["current_database"] = filename.split("/")[-1:][0]
826
+ self.pref["current_database"] = os.path.basename(filename)
747
827
  self.write_preference()
748
- self.dbname = DATA_PATH + "/" + self.pref.get("current_database", "ham.db")
749
- self.database = DataBase(self.dbname, WORKING_PATH)
828
+ self.dbname = fsutils.USER_DATA_PATH / self.pref.get(
829
+ "current_database", "ham.db"
830
+ )
831
+ self.database = DataBase(self.dbname, fsutils.APP_DATA_PATH)
750
832
  self.contact = self.database.empty_contact
751
833
  self.station = self.database.fetch_station()
752
834
  if self.station is None:
@@ -775,10 +857,12 @@ class MainWindow(QtWidgets.QMainWindow):
775
857
 
776
858
  filename = self.filepicker("open")
777
859
  if filename:
778
- self.pref["current_database"] = filename.split("/")[-1:][0]
860
+ self.pref["current_database"] = os.path.basename(filename)
779
861
  self.write_preference()
780
- self.dbname = DATA_PATH + "/" + self.pref.get("current_database", "ham.db")
781
- self.database = DataBase(self.dbname, WORKING_PATH)
862
+ self.dbname = fsutils.USER_DATA_PATH / self.pref.get(
863
+ "current_database", "ham.db"
864
+ )
865
+ self.database = DataBase(self.dbname, fsutils.MODULE_PATH)
782
866
  self.contact = self.database.empty_contact
783
867
  self.station = self.database.fetch_station()
784
868
  if self.station is None:
@@ -814,7 +898,10 @@ class MainWindow(QtWidgets.QMainWindow):
814
898
  logger.debug("%s", f"{contests}")
815
899
 
816
900
  if contests:
817
- self.contest_dialog = SelectContest(WORKING_PATH)
901
+ self.contest_dialog = SelectContest(fsutils.APP_DATA_PATH)
902
+ if self.current_palette:
903
+ self.contest_dialog.setPalette(self.current_palette)
904
+
818
905
  self.contest_dialog.contest_list.setRowCount(0)
819
906
  self.contest_dialog.contest_list.setColumnCount(4)
820
907
  self.contest_dialog.contest_list.verticalHeader().setVisible(False)
@@ -912,7 +999,14 @@ class MainWindow(QtWidgets.QMainWindow):
912
999
  return
913
1000
  if self.contest_settings is None:
914
1001
  return
915
- self.contest_dialog = NewContest(WORKING_PATH)
1002
+
1003
+ self.contest_dialog = NewContest(fsutils.APP_DATA_PATH)
1004
+ if self.current_palette:
1005
+ self.contest_dialog.setPalette(self.current_palette)
1006
+ self.contest_dialog.exchange.setPalette(self.current_palette)
1007
+ self.contest_dialog.operators.setPalette(self.current_palette)
1008
+ self.contest_dialog.contest.setPalette(self.current_palette)
1009
+
916
1010
  self.contest_dialog.setWindowTitle("Edit Contest")
917
1011
  self.contest_dialog.title.setText("")
918
1012
  self.contest_dialog.accepted.connect(self.save_edited_contest)
@@ -1078,7 +1172,7 @@ class MainWindow(QtWidgets.QMainWindow):
1078
1172
  """
1079
1173
 
1080
1174
  try:
1081
- cty = notctyparser.BigCty(WORKING_PATH + "/data/cty.json")
1175
+ cty = notctyparser.BigCty(fsutils.APP_DATA_PATH / "cty.json")
1082
1176
  update_available = cty.check_update()
1083
1177
  except (AttributeError, ValueError, locale.Error) as the_error:
1084
1178
  logger.debug("cty parser returned an error: %s", the_error)
@@ -1092,10 +1186,10 @@ class MainWindow(QtWidgets.QMainWindow):
1092
1186
  logger.debug("cty parser returned an error: %s", the_error)
1093
1187
  return
1094
1188
  if updated:
1095
- cty.dump(WORKING_PATH + "/data/cty.json")
1189
+ cty.dump(fsutils.APP_DATA_PATH / "cty.json")
1096
1190
  self.show_message_box("cty file updated.")
1097
1191
  with open(
1098
- WORKING_PATH + "/data/cty.json", "rt", encoding="utf-8"
1192
+ fsutils.APP_DATA_PATH / "cty.json", "rt", encoding="utf-8"
1099
1193
  ) as ctyfile:
1100
1194
  globals()["CTYFILE"] = loads(ctyfile.read())
1101
1195
  else:
@@ -1198,7 +1292,7 @@ class MainWindow(QtWidgets.QMainWindow):
1198
1292
  file, _ = QFileDialog.getSaveFileName(
1199
1293
  self,
1200
1294
  "Choose a Database",
1201
- DATA_PATH,
1295
+ str(fsutils.USER_DATA_PATH),
1202
1296
  "Database (*.db)",
1203
1297
  options=options,
1204
1298
  )
@@ -1206,7 +1300,7 @@ class MainWindow(QtWidgets.QMainWindow):
1206
1300
  file, _ = QFileDialog.getOpenFileName(
1207
1301
  self,
1208
1302
  "Choose a Database",
1209
- DATA_PATH,
1303
+ str(fsutils.USER_DATA_PATH),
1210
1304
  "Database (*.db)",
1211
1305
  options=options,
1212
1306
  )
@@ -1218,24 +1312,38 @@ class MainWindow(QtWidgets.QMainWindow):
1218
1312
  self.clearinputs()
1219
1313
 
1220
1314
  def launch_log_window(self) -> None:
1221
- """launch the Log Window"""
1222
- if not check_process("logwindow.py"):
1223
- _ = subprocess.Popen([sys.executable, WORKING_PATH + "/logwindow.py"])
1315
+ """Launch the log window"""
1316
+ if not self.log_window:
1317
+ log_widget = LogWindow()
1318
+ self.log_window = QDockWidget(log_widget.property("windowTitle"), self)
1319
+ self.log_window.setWidget(log_widget)
1320
+ self.addDockWidget(Qt.BottomDockWidgetArea, self.log_window)
1321
+ self.log_window.show()
1224
1322
 
1225
1323
  def launch_bandmap_window(self) -> None:
1226
- """launch the Log Window"""
1227
- if not check_process("bandmap.py"):
1228
- _ = subprocess.Popen([sys.executable, WORKING_PATH + "/bandmap.py"])
1324
+ """Launch the bandmap window"""
1325
+ if not self.bandmap_window:
1326
+ self.bandmap_window = BandMapWindow()
1327
+ self.addDockWidget(Qt.RightDockWidgetArea, self.bandmap_window)
1328
+ self.bandmap_window.show()
1229
1329
 
1230
1330
  def launch_check_window(self) -> None:
1231
- """launch the Log Window"""
1232
- if not check_process("checkwindow.py"):
1233
- _ = subprocess.Popen([sys.executable, WORKING_PATH + "/checkwindow.py"])
1331
+ """Launch the check window"""
1332
+ if not self.check_window:
1333
+ check_widget = CheckWindow()
1334
+ self.check_window = QDockWidget(check_widget.property("windowTitle"), self)
1335
+ self.check_window.setWidget(check_widget)
1336
+ self.addDockWidget(Qt.RightDockWidgetArea, self.check_window)
1337
+ self.check_window.show()
1234
1338
 
1235
1339
  def launch_vfo(self) -> None:
1236
- """launch the Log Window"""
1237
- if not check_process("vfo.py"):
1238
- _ = subprocess.Popen([sys.executable, WORKING_PATH + "/vfo.py"])
1340
+ """Launch the VFO window"""
1341
+ if not self.vfo_window:
1342
+ vfo_widget = VfoWindow()
1343
+ self.vfo_window = QDockWidget(vfo_widget.property("windowTitle"), self)
1344
+ self.vfo_window.setWidget(vfo_widget)
1345
+ self.addDockWidget(Qt.RightDockWidgetArea, self.vfo_window)
1346
+ self.vfo_window.show()
1239
1347
 
1240
1348
  def clear_band_indicators(self) -> None:
1241
1349
  """
@@ -1252,7 +1360,12 @@ class MainWindow(QtWidgets.QMainWindow):
1252
1360
  for _, indicators in self.all_mode_indicators.items():
1253
1361
  for _, indicator in indicators.items():
1254
1362
  indicator.setFrameShape(QtWidgets.QFrame.NoFrame)
1255
- indicator.setStyleSheet("font-family: JetBrains Mono;")
1363
+ if self.text_color == Qt.black:
1364
+ indicator.setStyleSheet(
1365
+ "font-family: JetBrains Mono; color: black;"
1366
+ )
1367
+ else:
1368
+ indicator.setStyleSheet("font-family: JetBrains Mono; color: white")
1256
1369
 
1257
1370
  def set_band_indicator(self, band: str) -> None:
1258
1371
  """
@@ -1739,7 +1852,13 @@ class MainWindow(QtWidgets.QMainWindow):
1739
1852
  """
1740
1853
 
1741
1854
  logger.debug("New contest Dialog")
1742
- self.contest_dialog = NewContest(WORKING_PATH)
1855
+
1856
+ self.contest_dialog = NewContest(fsutils.APP_DATA_PATH)
1857
+ if self.current_palette:
1858
+ self.contest_dialog.setPalette(self.current_palette)
1859
+ self.contest_dialog.exchange.setPalette(self.current_palette)
1860
+ self.contest_dialog.operators.setPalette(self.current_palette)
1861
+
1743
1862
  self.contest_dialog.accepted.connect(self.save_contest)
1744
1863
  self.contest_dialog.dateTimeEdit.setDate(QtCore.QDate.currentDate())
1745
1864
  self.contest_dialog.dateTimeEdit.setCalendarPopup(True)
@@ -1804,7 +1923,11 @@ class MainWindow(QtWidgets.QMainWindow):
1804
1923
  """
1805
1924
 
1806
1925
  logger.debug("Station Settings selected")
1807
- self.settings_dialog = EditStation(WORKING_PATH)
1926
+
1927
+ self.settings_dialog = EditStation(fsutils.APP_DATA_PATH)
1928
+ if self.current_palette:
1929
+ self.settings_dialog.setPalette(self.current_palette)
1930
+
1808
1931
  self.settings_dialog.accepted.connect(self.save_settings)
1809
1932
  self.settings_dialog.Call.setText(self.station.get("Call", ""))
1810
1933
  self.settings_dialog.Name.setText(self.station.get("Name", ""))
@@ -1892,7 +2015,11 @@ class MainWindow(QtWidgets.QMainWindow):
1892
2015
  None
1893
2016
  """
1894
2017
 
1895
- self.edit_macro_dialog = EditMacro(function_key, WORKING_PATH)
2018
+ self.edit_macro_dialog = EditMacro(function_key, fsutils.APP_DATA_PATH)
2019
+
2020
+ if self.current_palette:
2021
+ self.edit_macro_dialog.setPalette(self.current_palette)
2022
+
1896
2023
  self.edit_macro_dialog.accepted.connect(self.edited_macro)
1897
2024
  self.edit_macro_dialog.open()
1898
2025
 
@@ -1965,7 +2092,7 @@ class MainWindow(QtWidgets.QMainWindow):
1965
2092
  """
1966
2093
 
1967
2094
  logger.debug("Voicing: %s", the_string)
1968
- op_path = Path(DATA_PATH) / self.current_op
2095
+ op_path = fsutils.USER_DATA_PATH / self.current_op
1969
2096
  if "[" in the_string:
1970
2097
  sub_string = the_string.strip("[]").lower()
1971
2098
  filename = f"{str(op_path)}/{sub_string}.wav"
@@ -2093,11 +2220,9 @@ class MainWindow(QtWidgets.QMainWindow):
2093
2220
 
2094
2221
  logger.debug("writepreferences")
2095
2222
  try:
2096
- with open(
2097
- CONFIG_PATH + "/not1mm.json", "wt", encoding="utf-8"
2098
- ) as file_descriptor:
2223
+ with open(fsutils.CONFIG_FILE, "wt", encoding="utf-8") as file_descriptor:
2099
2224
  file_descriptor.write(dumps(self.pref, indent=4))
2100
- logger.info("writing: %s", self.pref)
2225
+ # logger.info("writing: %s", self.pref)
2101
2226
  except IOError as exception:
2102
2227
  logger.critical("writepreferences: %s", exception)
2103
2228
 
@@ -2116,16 +2241,16 @@ class MainWindow(QtWidgets.QMainWindow):
2116
2241
 
2117
2242
  logger.debug("readpreferences")
2118
2243
  try:
2119
- if os.path.exists(CONFIG_PATH + "/not1mm.json"):
2244
+ if os.path.exists(fsutils.CONFIG_FILE):
2120
2245
  with open(
2121
- CONFIG_PATH + "/not1mm.json", "rt", encoding="utf-8"
2246
+ fsutils.CONFIG_FILE, "rt", encoding="utf-8"
2122
2247
  ) as file_descriptor:
2123
2248
  self.pref = loads(file_descriptor.read())
2124
2249
  logger.info("%s", self.pref)
2125
2250
  else:
2126
2251
  logger.info("No preference file. Writing preference.")
2127
2252
  with open(
2128
- CONFIG_PATH + "/not1mm.json", "wt", encoding="utf-8"
2253
+ fsutils.CONFIG_FILE, "wt", encoding="utf-8"
2129
2254
  ) as file_descriptor:
2130
2255
  self.pref = self.pref_ref.copy()
2131
2256
  file_descriptor.write(dumps(self.pref, indent=4))
@@ -2173,6 +2298,13 @@ class MainWindow(QtWidgets.QMainWindow):
2173
2298
  )
2174
2299
  self.multicast_interface.ready_read_connect(self.watch_udp)
2175
2300
 
2301
+ if self.pref.get("darkmode"):
2302
+ self.actionDark_Mode_2.setChecked(True)
2303
+ self.setDarkMode(True)
2304
+ else:
2305
+ self.setDarkMode(False)
2306
+ self.actionDark_Mode_2.setChecked(False)
2307
+
2176
2308
  self.rig_control = None
2177
2309
 
2178
2310
  if self.pref.get("useflrig", False):
@@ -2300,6 +2432,24 @@ class MainWindow(QtWidgets.QMainWindow):
2300
2432
  cmd["worked"] = result
2301
2433
  self.multicast_interface.send_as_json(cmd)
2302
2434
 
2435
+ if (
2436
+ json_data.get("cmd", "") == "GETCONTESTSTATUS"
2437
+ and json_data.get("station", "") == platform.node()
2438
+ ):
2439
+ cmd = {
2440
+ "cmd": "CONTESTSTATUS",
2441
+ "station": platform.node(),
2442
+ "contest": self.contest_settings,
2443
+ "operator": self.current_op,
2444
+ }
2445
+ self.multicast_interface.send_as_json(cmd)
2446
+
2447
+ def dark_mode_state_changed(self) -> None:
2448
+ """Called when the Dark Mode menu state is changed."""
2449
+ self.pref["darkmode"] = self.actionDark_Mode_2.isChecked()
2450
+ self.write_preference()
2451
+ self.setDarkMode(self.actionDark_Mode_2.isChecked())
2452
+
2303
2453
  def cw_macros_state_changed(self) -> None:
2304
2454
  """
2305
2455
  Menu item to show/hide macro buttons.
@@ -2769,7 +2919,11 @@ class MainWindow(QtWidgets.QMainWindow):
2769
2919
  None
2770
2920
  """
2771
2921
 
2772
- self.opon_dialog = OpOn(WORKING_PATH)
2922
+ self.opon_dialog = OpOn(fsutils.APP_DATA_PATH)
2923
+
2924
+ if self.current_palette:
2925
+ self.opon_dialog.setPalette(self.current_palette)
2926
+
2773
2927
  self.opon_dialog.accepted.connect(self.new_op)
2774
2928
  self.opon_dialog.open()
2775
2929
 
@@ -2808,13 +2962,13 @@ class MainWindow(QtWidgets.QMainWindow):
2808
2962
  """
2809
2963
 
2810
2964
  if self.current_op:
2811
- op_path = Path(DATA_PATH) / self.current_op
2965
+ op_path = fsutils.USER_DATA_PATH / self.current_op
2812
2966
  logger.debug("op_path: %s", str(op_path))
2813
2967
  if op_path.is_dir() is False:
2814
2968
  logger.debug("Creating Op Directory: %s", str(op_path))
2815
2969
  os.mkdir(str(op_path))
2816
2970
  if op_path.is_dir():
2817
- source_path = Path(WORKING_PATH) / "data" / "phonetics"
2971
+ source_path = fsutils.APP_DATA_PATH / "phonetics"
2818
2972
  logger.debug("source_path: %s", str(source_path))
2819
2973
  for child in source_path.iterdir():
2820
2974
  destination_file = op_path / child.name
@@ -2911,13 +3065,20 @@ class MainWindow(QtWidgets.QMainWindow):
2911
3065
  None
2912
3066
  """
2913
3067
  if self.radio_state.get("mode") == "CW":
2914
- macro_file = "/cwmacros.txt"
3068
+ macro_file = "cwmacros.txt"
2915
3069
  else:
2916
- macro_file = "/ssbmacros.txt"
2917
- if not Path(DATA_PATH + macro_file).exists():
3070
+ macro_file = "ssbmacros.txt"
3071
+ if not (fsutils.USER_DATA_PATH / macro_file).exists():
2918
3072
  logger.debug("read_cw_macros: copying default macro file.")
2919
- copyfile(WORKING_PATH + "/data" + macro_file, DATA_PATH + macro_file)
2920
- os.system(f"xdg-open {DATA_PATH}{macro_file}")
3073
+ copyfile(
3074
+ fsutils.APP_DATA_PATH / macro_file, fsutils.USER_DATA_PATH / macro_file
3075
+ )
3076
+ try:
3077
+ fsutils.openFileWithOS(fsutils.USER_DATA_PATH / macro_file)
3078
+ except:
3079
+ logger.exception(
3080
+ f"Could not open file {fsutils.USER_DATA_PATH / macro_file}"
3081
+ )
2921
3082
 
2922
3083
  def read_cw_macros(self) -> None:
2923
3084
  """
@@ -2927,14 +3088,18 @@ class MainWindow(QtWidgets.QMainWindow):
2927
3088
  """
2928
3089
 
2929
3090
  if self.radio_state.get("mode") == "CW":
2930
- macro_file = "/cwmacros.txt"
3091
+ macro_file = "cwmacros.txt"
2931
3092
  else:
2932
- macro_file = "/ssbmacros.txt"
3093
+ macro_file = "ssbmacros.txt"
2933
3094
 
2934
- if not Path(DATA_PATH + macro_file).exists():
3095
+ if not (fsutils.USER_DATA_PATH / macro_file).exists():
2935
3096
  logger.debug("read_cw_macros: copying default macro file.")
2936
- copyfile(WORKING_PATH + "/data" + macro_file, DATA_PATH + macro_file)
2937
- with open(DATA_PATH + macro_file, "r", encoding="utf-8") as file_descriptor:
3097
+ copyfile(
3098
+ fsutils.APP_DATA_PATH / macro_file, fsutils.USER_DATA_PATH / macro_file
3099
+ )
3100
+ with open(
3101
+ fsutils.USER_DATA_PATH / macro_file, "r", encoding="utf-8"
3102
+ ) as file_descriptor:
2938
3103
  for line in file_descriptor:
2939
3104
  try:
2940
3105
  mode, fkey, buttonname, cwtext = line.split("|")
@@ -3043,17 +3208,19 @@ def install_icons() -> None:
3043
3208
  if sys.platform == "linux":
3044
3209
  os.system(
3045
3210
  "xdg-icon-resource install --size 32 --context apps --mode user "
3046
- f"{WORKING_PATH}/data/k6gte.not1mm-32.png k6gte-not1mm"
3211
+ f"{fsutils.MODULE_PATH}/data/k6gte.not1mm-32.png k6gte-not1mm"
3047
3212
  )
3048
3213
  os.system(
3049
3214
  "xdg-icon-resource install --size 64 --context apps --mode user "
3050
- f"{WORKING_PATH}/data/k6gte.not1mm-64.png k6gte-not1mm"
3215
+ f"{fsutils.MODULE_PATH}/data/k6gte.not1mm-64.png k6gte-not1mm"
3051
3216
  )
3052
3217
  os.system(
3053
3218
  "xdg-icon-resource install --size 128 --context apps --mode user "
3054
- f"{WORKING_PATH}/data/k6gte.not1mm-128.png k6gte-not1mm"
3219
+ f"{fsutils.MODULE_PATH}/data/k6gte.not1mm-128.png k6gte-not1mm"
3220
+ )
3221
+ os.system(
3222
+ f"xdg-desktop-menu install {fsutils.MODULE_PATH}/data/k6gte-not1mm.desktop"
3055
3223
  )
3056
- os.system(f"xdg-desktop-menu install {WORKING_PATH}/data/k6gte-not1mm.desktop")
3057
3224
 
3058
3225
 
3059
3226
  def doimp(modname) -> object:
@@ -3079,36 +3246,35 @@ def run() -> None:
3079
3246
  """
3080
3247
  Main Entry
3081
3248
  """
3249
+ logger.debug(
3250
+ f"Resolved OS file system paths: MODULE_PATH {fsutils.MODULE_PATH}, USER_DATA_PATH {fsutils.USER_DATA_PATH}, CONFIG_PATH {fsutils.CONFIG_PATH}"
3251
+ )
3082
3252
  install_icons()
3083
3253
  timer.start(250)
3084
3254
  sys.exit(app.exec())
3085
3255
 
3086
3256
 
3087
- logger = logging.getLogger("__main__")
3088
- handler = logging.StreamHandler()
3089
- formatter = logging.Formatter(
3090
- datefmt="%H:%M:%S",
3091
- fmt="[%(asctime)s] %(levelname)s %(module)s - %(funcName)s Line %(lineno)d: %(message)s",
3092
- )
3093
- handler.setFormatter(formatter)
3094
- logger.addHandler(handler)
3095
-
3096
- BETA_TEST = False
3097
- if Path("./betatest").exists():
3098
- BETA_TEST = True
3099
-
3257
+ DEBUG_ENABLED = False
3100
3258
  if Path("./debug").exists():
3101
- logger.setLevel(logging.DEBUG)
3102
- logger.debug("debugging on")
3103
- else:
3104
- logger.setLevel(logging.WARNING)
3105
- # logger.warning("debugging off")
3259
+ DEBUG_ENABLED = True
3106
3260
 
3261
+ logger = logging.getLogger("__main__")
3262
+
3263
+ logging.basicConfig(
3264
+ level=logging.DEBUG if DEBUG_ENABLED else logging.CRITICAL,
3265
+ format="[%(asctime)s] %(levelname)s %(name)s - %(funcName)s Line %(lineno)d: %(message)s",
3266
+ handlers=[
3267
+ RotatingFileHandler(fsutils.LOG_FILE, maxBytes=10490000, backupCount=20),
3268
+ logging.StreamHandler(),
3269
+ ],
3270
+ )
3271
+ logging.getLogger("PyQt5.uic.uiparser").setLevel("INFO")
3272
+ logging.getLogger("PyQt5.uic.properties").setLevel("INFO")
3273
+ os.environ["QT_QPA_PLATFORMTHEME"] = "gnome"
3107
3274
  app = QtWidgets.QApplication(sys.argv)
3108
- app.setStyle("Adwaita-Dark")
3109
- font_path = WORKING_PATH + "/data"
3110
- families = load_fonts_from_dir(os.fspath(font_path))
3111
- logger.info(families)
3275
+
3276
+ families = load_fonts_from_dir(os.fspath(fsutils.APP_DATA_PATH))
3277
+ logger.info(f"font families {families}")
3112
3278
  window = MainWindow()
3113
3279
  height = window.pref.get("window_height", 300)
3114
3280
  width = window.pref.get("window_width", 700)