From 9143afc1762f02918dc24380839aaf82cdf2da38 Mon Sep 17 00:00:00 2001
From: Roland W-H <r.weirhowell@gmail.com>
Date: Tue, 11 Feb 2025 10:57:19 +0000
Subject: [PATCH 1/8] begin adding optional fields

---
 gui/platform_edit.ui | 201 ++++++++++++++++++++++++++++++-------------
 src/platform_edit.py |  18 +++-
 2 files changed, 156 insertions(+), 63 deletions(-)

diff --git a/gui/platform_edit.ui b/gui/platform_edit.ui
index 0cc4a1f..6233405 100644
--- a/gui/platform_edit.ui
+++ b/gui/platform_edit.ui
@@ -53,13 +53,6 @@
     <property name="verticalSpacing">
      <number>5</number>
     </property>
-    <item row="0" column="0" colspan="2">
-     <widget class="QLabel" name="plat_name_lab">
-      <property name="text">
-       <string>Platform name</string>
-      </property>
-     </widget>
-    </item>
     <item row="8" column="0" colspan="2">
      <widget class="QLabel" name="share_deal_reduce_amount_lab">
       <property name="text">
@@ -67,44 +60,6 @@
       </property>
      </widget>
     </item>
-    <item row="0" column="2">
-     <widget class="QLineEdit" name="plat_name_box"/>
-    </item>
-    <item row="3" column="0" colspan="2">
-     <widget class="QLabel" name="share_plat_fee_lab">
-      <property name="text">
-       <string>Share platform fee*</string>
-      </property>
-     </widget>
-    </item>
-    <item row="7" column="0" colspan="2">
-     <widget class="QLabel" name="share_deal_reduce_trades_lab">
-      <property name="text">
-       <string>Share dealing discount # of trades</string>
-      </property>
-     </widget>
-    </item>
-    <item row="5" column="0" colspan="2">
-     <widget class="QLabel" name="share_deal_fee_lab">
-      <property name="text">
-       <string>Share dealing fee*</string>
-      </property>
-     </widget>
-    </item>
-    <item row="1" column="0" colspan="2">
-     <widget class="QLabel" name="fund_deal_fee_lab">
-      <property name="text">
-       <string>Fund dealing fee*</string>
-      </property>
-     </widget>
-    </item>
-    <item row="4" column="0" colspan="2">
-     <widget class="QLabel" name="share_plat_max_fee_lab">
-      <property name="text">
-       <string>Share platform fee cap/mth</string>
-      </property>
-     </widget>
-    </item>
     <item row="8" column="2">
      <widget class="QDoubleSpinBox" name="share_deal_reduce_amount_box">
       <property name="buttonSymbols">
@@ -118,19 +73,6 @@
       </property>
      </widget>
     </item>
-    <item row="5" column="2">
-     <widget class="QDoubleSpinBox" name="share_deal_fee_box">
-      <property name="buttonSymbols">
-       <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
-      </property>
-      <property name="correctionMode">
-       <enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
-      </property>
-      <property name="prefix">
-       <string>£</string>
-      </property>
-     </widget>
-    </item>
     <item row="4" column="2">
      <widget class="QDoubleSpinBox" name="share_plat_max_fee_box">
       <property name="buttonSymbols">
@@ -144,16 +86,49 @@
       </property>
      </widget>
     </item>
-    <item row="3" column="2">
-     <widget class="QDoubleSpinBox" name="share_plat_fee_box">
+    <item row="0" column="3">
+     <widget class="QCheckBox" name="plat_name_check">
+      <property name="text">
+       <string/>
+      </property>
+      <property name="checked">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="0" colspan="2">
+     <widget class="QLabel" name="plat_name_lab">
+      <property name="text">
+       <string>Platform name</string>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="2">
+     <widget class="QLineEdit" name="plat_name_box"/>
+    </item>
+    <item row="3" column="3">
+     <widget class="QCheckBox" name="share_plat_fee_check">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
+      <property name="text">
+       <string/>
+      </property>
+      <property name="checked">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+    <item row="5" column="2">
+     <widget class="QDoubleSpinBox" name="share_deal_fee_box">
       <property name="buttonSymbols">
        <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
       </property>
       <property name="correctionMode">
        <enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
       </property>
-      <property name="suffix">
-       <string>%</string>
+      <property name="prefix">
+       <string>£</string>
       </property>
      </widget>
     </item>
@@ -170,6 +145,47 @@
       </property>
      </widget>
     </item>
+    <item row="1" column="0" colspan="2">
+     <widget class="QLabel" name="fund_deal_fee_lab">
+      <property name="text">
+       <string>Fund dealing fee*</string>
+      </property>
+     </widget>
+    </item>
+    <item row="4" column="0" colspan="2">
+     <widget class="QLabel" name="share_plat_max_fee_lab">
+      <property name="text">
+       <string>Share platform fee cap/mth</string>
+      </property>
+     </widget>
+    </item>
+    <item row="3" column="2">
+     <widget class="QDoubleSpinBox" name="share_plat_fee_box">
+      <property name="buttonSymbols">
+       <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
+      </property>
+      <property name="correctionMode">
+       <enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
+      </property>
+      <property name="suffix">
+       <string>%</string>
+      </property>
+     </widget>
+    </item>
+    <item row="7" column="3">
+     <widget class="QCheckBox" name="share_deal_reduce_trades_check">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="5" column="0" colspan="2">
+     <widget class="QLabel" name="share_deal_fee_lab">
+      <property name="text">
+       <string>Share dealing fee*</string>
+      </property>
+     </widget>
+    </item>
     <item row="7" column="2">
      <widget class="QSpinBox" name="share_deal_reduce_trades_box">
       <property name="buttonSymbols">
@@ -180,6 +196,60 @@
       </property>
      </widget>
     </item>
+    <item row="7" column="0" colspan="2">
+     <widget class="QLabel" name="share_deal_reduce_trades_lab">
+      <property name="text">
+       <string>Share dealing discount # of trades</string>
+      </property>
+     </widget>
+    </item>
+    <item row="8" column="3">
+     <widget class="QCheckBox" name="share_deal_reduce_amount_check">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="5" column="3">
+     <widget class="QCheckBox" name="share_deal_fee_check">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
+      <property name="text">
+       <string/>
+      </property>
+      <property name="checked">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+    <item row="3" column="0" colspan="2">
+     <widget class="QLabel" name="share_plat_fee_lab">
+      <property name="text">
+       <string>Share platform fee*</string>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="3">
+     <widget class="QCheckBox" name="fund_deal_fee_check">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
+      <property name="text">
+       <string/>
+      </property>
+      <property name="checked">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+    <item row="4" column="3">
+     <widget class="QCheckBox" name="share_plat_max_fee_check">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
    </layout>
   </widget>
   <widget class="QPushButton" name="save_but">
@@ -221,6 +291,13 @@
   <tabstop>share_deal_reduce_trades_box</tabstop>
   <tabstop>share_deal_reduce_amount_box</tabstop>
   <tabstop>save_but</tabstop>
+  <tabstop>plat_name_check</tabstop>
+  <tabstop>fund_deal_fee_check</tabstop>
+  <tabstop>share_plat_fee_check</tabstop>
+  <tabstop>share_plat_max_fee_check</tabstop>
+  <tabstop>share_deal_fee_check</tabstop>
+  <tabstop>share_deal_reduce_trades_check</tabstop>
+  <tabstop>share_deal_reduce_amount_check</tabstop>
  </tabstops>
  <resources/>
  <connections>
diff --git a/src/platform_edit.py b/src/platform_edit.py
index fda14dd..7989e83 100644
--- a/src/platform_edit.py
+++ b/src/platform_edit.py
@@ -30,6 +30,13 @@ class PlatformEdit(QWidget):
         if autofill:
             self.save_but.setEnabled(True)
 
+        self.optional_check_boxes = [
+            self.plat_name_check,
+            self.share_plat_max_fee_check,
+            self.share_deal_reduce_trades_check,
+            self.share_deal_reduce_amount_check
+        ]
+
         # Create main window object, passing this instance as param
         self.main_win = main_window.SIPPCompare(self)
 
@@ -40,6 +47,9 @@ class PlatformEdit(QWidget):
         self.share_plat_fee_box.valueChanged.connect(self.check_valid)
         self.share_deal_fee_box.valueChanged.connect(self.check_valid)
 
+        for check_box in self.optional_check_boxes:
+            check_box.checkStateChanged.connect(self.check_valid)
+
         # Install event filter on input boxes in order to select all text on focus
         self.fund_deal_fee_box.installEventFilter(self)
         self.share_plat_fee_box.installEventFilter(self)
@@ -48,6 +58,9 @@ class PlatformEdit(QWidget):
         self.share_deal_reduce_trades_box.installEventFilter(self)
         self.share_deal_reduce_amount_box.installEventFilter(self)
 
+        #for check_box in self.optional_check_boxes:
+        #    check_box.installEventFilter(self)
+
         # Set validators
         # Regex accepts any characters that match [a-Z], [0-9] or _
         self.plat_name_box.setValidator(
@@ -79,10 +92,13 @@ class PlatformEdit(QWidget):
 
     # When focus is given to an input box, select all text in it (easier to edit)
     def eventFilter(self, obj: QObject, event: QEvent):
-        if event.type() == QEvent.Type.FocusIn:
+        if obj.staticMetaObject.className() == "QDoubleSpinBox" and event.type() == QEvent.Type.FocusIn:
             # Alternative condition for % suffix - currently unused
             #if obj.value() == 0 or obj == self.share_plat_fee_box:
             QTimer.singleShot(0, obj.selectAll)
+        #if obj in self.optional_check_boxes and \
+        #event.type() == QEvent.Type.FocusIn or event.type() == QEvent.Type.FocusOut:
+         #   print("Working")
         return False
 
     # Check if all required fields have valid (non-zero) input

From ecc2ce6d566e9ec6cb15df35d5147e6e088d4d34 Mon Sep 17 00:00:00 2001
From: Roland W-H <r.weirhowell@gmail.com>
Date: Tue, 11 Feb 2025 13:42:35 +0000
Subject: [PATCH 2/8] continue implementing optional fields - still broken

---
 src/platform_edit.py | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/src/platform_edit.py b/src/platform_edit.py
index 7989e83..e5dd0f9 100644
--- a/src/platform_edit.py
+++ b/src/platform_edit.py
@@ -1,6 +1,6 @@
 from PyQt6.QtCore import QRegularExpression, QEvent, QObject, QTimer
 from PyQt6.QtGui import QRegularExpressionValidator
-from PyQt6.QtWidgets import QWidget
+from PyQt6.QtWidgets import QWidget, QLayout
 from PyQt6 import uic
 
 import main_window
@@ -37,6 +37,12 @@ class PlatformEdit(QWidget):
             self.share_deal_reduce_amount_check
         ]
 
+        self.required_fields = [
+            self.fund_deal_fee_box,
+            self.share_plat_fee_box,
+            self.share_deal_fee_box
+        ]
+
         # Create main window object, passing this instance as param
         self.main_win = main_window.SIPPCompare(self)
 
@@ -104,16 +110,27 @@ class PlatformEdit(QWidget):
     # Check if all required fields have valid (non-zero) input
     # TODO: Find a better way of doing this if possible
     def check_valid(self):
-        values = [self.fund_deal_fee_box.value(),
-                  self.share_plat_fee_box.value(),
-                  self.share_deal_fee_box.value()
-                ]
         valid = True
 
-        for value in values:
-            if value == 0:
+        for field in self.required_fields:
+            if field.value() == 0:
                 valid = False
 
+        for check_box in self.optional_check_boxes:
+            if check_box.isChecked():
+                check_box_pos = self.gridLayout.getItemPosition(
+                    self.gridLayout.indexOf(check_box)
+                )
+                input_box_pos = list(check_box_pos)[:2]
+                input_box_pos[1] -= 1
+                input_box_item = self.gridLayout.itemAtPosition(input_box_pos[0], input_box_pos[1]).widget()
+                if input_box_item.staticMetaObject.className() == "QLineEdit":
+                    if input_box_item.text() == "":
+                        valid = False
+                elif input_box_item.staticMetaObject.className() == "QDoubleSpinBox":
+                    if input_box_item.value() == 0:
+                        valid = False
+
         if valid:
             self.save_but.setEnabled(True)
         else:

From fcbc78b05b2448c6d97555ff77801566f8c45088 Mon Sep 17 00:00:00 2001
From: Roland W-H <r.weirhowell@gmail.com>
Date: Tue, 11 Feb 2025 15:52:36 +0000
Subject: [PATCH 3/8] opt field input validation complete - functionality still
 TODO

---
 gui/platform_edit.ui |  9 ++++++++
 src/platform_edit.py | 55 ++++++++++++++++++++++++++------------------
 2 files changed, 42 insertions(+), 22 deletions(-)

diff --git a/gui/platform_edit.ui b/gui/platform_edit.ui
index 6233405..abd0088 100644
--- a/gui/platform_edit.ui
+++ b/gui/platform_edit.ui
@@ -62,6 +62,9 @@
     </item>
     <item row="8" column="2">
      <widget class="QDoubleSpinBox" name="share_deal_reduce_amount_box">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
       <property name="buttonSymbols">
        <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
       </property>
@@ -75,6 +78,9 @@
     </item>
     <item row="4" column="2">
      <widget class="QDoubleSpinBox" name="share_plat_max_fee_box">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
       <property name="buttonSymbols">
        <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
       </property>
@@ -188,6 +194,9 @@
     </item>
     <item row="7" column="2">
      <widget class="QSpinBox" name="share_deal_reduce_trades_box">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
       <property name="buttonSymbols">
        <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
       </property>
diff --git a/src/platform_edit.py b/src/platform_edit.py
index e5dd0f9..846551d 100644
--- a/src/platform_edit.py
+++ b/src/platform_edit.py
@@ -30,6 +30,19 @@ class PlatformEdit(QWidget):
         if autofill:
             self.save_but.setEnabled(True)
 
+        self.required_fields = [
+            self.fund_deal_fee_box,
+            self.share_plat_fee_box,
+            self.share_deal_fee_box
+        ]
+
+        self.optional_fields = [
+            self.plat_name_box,
+            self.share_plat_max_fee_box,
+            self.share_deal_reduce_trades_box,
+            self.share_deal_reduce_amount_box
+        ]
+
         self.optional_check_boxes = [
             self.plat_name_check,
             self.share_plat_max_fee_check,
@@ -37,21 +50,21 @@ class PlatformEdit(QWidget):
             self.share_deal_reduce_amount_check
         ]
 
-        self.required_fields = [
-            self.fund_deal_fee_box,
-            self.share_plat_fee_box,
-            self.share_deal_fee_box
-        ]
-
         # Create main window object, passing this instance as param
         self.main_win = main_window.SIPPCompare(self)
 
         # Handle events
         # NOTE: Signal defined in UI file to close window when save button clicked
         self.save_but.clicked.connect(self.init_variables)
-        self.fund_deal_fee_box.valueChanged.connect(self.check_valid)
-        self.share_plat_fee_box.valueChanged.connect(self.check_valid)
-        self.share_deal_fee_box.valueChanged.connect(self.check_valid)
+
+        for field in self.required_fields:
+            field.valueChanged.connect(self.check_valid)
+
+        for field in self.optional_fields:
+            if field.staticMetaObject.className() == "QLineEdit":
+                field.textChanged.connect(self.check_valid)
+            elif field.staticMetaObject.className() == "QDoubleSpinBox":
+                field.valueChanged.connect(self.check_valid)
 
         for check_box in self.optional_check_boxes:
             check_box.checkStateChanged.connect(self.check_valid)
@@ -98,17 +111,13 @@ class PlatformEdit(QWidget):
 
     # When focus is given to an input box, select all text in it (easier to edit)
     def eventFilter(self, obj: QObject, event: QEvent):
-        if obj.staticMetaObject.className() == "QDoubleSpinBox" and event.type() == QEvent.Type.FocusIn:
+        if event.type() == QEvent.Type.FocusIn:
             # Alternative condition for % suffix - currently unused
             #if obj.value() == 0 or obj == self.share_plat_fee_box:
             QTimer.singleShot(0, obj.selectAll)
-        #if obj in self.optional_check_boxes and \
-        #event.type() == QEvent.Type.FocusIn or event.type() == QEvent.Type.FocusOut:
-         #   print("Working")
         return False
 
     # Check if all required fields have valid (non-zero) input
-    # TODO: Find a better way of doing this if possible
     def check_valid(self):
         valid = True
 
@@ -117,19 +126,21 @@ class PlatformEdit(QWidget):
                 valid = False
 
         for check_box in self.optional_check_boxes:
+            check_box_pos = self.gridLayout.getItemPosition(self.gridLayout.indexOf(check_box))
+            input_box_pos = list(check_box_pos)[:2]
+            input_box_pos[1] -= 1
+            input_box_item = self.gridLayout.itemAtPosition(input_box_pos[0], input_box_pos[1]).widget()
             if check_box.isChecked():
-                check_box_pos = self.gridLayout.getItemPosition(
-                    self.gridLayout.indexOf(check_box)
-                )
-                input_box_pos = list(check_box_pos)[:2]
-                input_box_pos[1] -= 1
-                input_box_item = self.gridLayout.itemAtPosition(input_box_pos[0], input_box_pos[1]).widget()
-                if input_box_item.staticMetaObject.className() == "QLineEdit":
+                input_box_item.setEnabled(True)
+                input_box_type = input_box_item.staticMetaObject.className()
+                if input_box_type == "QLineEdit":
                     if input_box_item.text() == "":
                         valid = False
-                elif input_box_item.staticMetaObject.className() == "QDoubleSpinBox":
+                elif input_box_type == "QDoubleSpinBox" or input_box_type == "QSpinBox":
                     if input_box_item.value() == 0:
                         valid = False
+            else:
+                input_box_item.setEnabled(False)
 
         if valid:
             self.save_but.setEnabled(True)

From 36a36f5437441b3416cec10c84a8181b89716ac0 Mon Sep 17 00:00:00 2001
From: Roland W-H <r.weirhowell@gmail.com>
Date: Tue, 11 Feb 2025 18:11:54 +0000
Subject: [PATCH 4/8] implemented optional fields - needs further work

---
 src/main_window.py   | 42 +++++++++++++++++++++++---------
 src/output_window.py | 12 ++++++++--
 src/platform_edit.py | 57 ++++++++++++++++++++++++++++++++------------
 3 files changed, 83 insertions(+), 28 deletions(-)

diff --git a/src/main_window.py b/src/main_window.py
index 14060e3..a012427 100644
--- a/src/main_window.py
+++ b/src/main_window.py
@@ -14,6 +14,7 @@ class SIPPCompare(QMainWindow):
 
         # Initialise class variables
         # Inputs
+        self.optional_boxes             = []
         self.fund_plat_fee              = 0.0
         self.plat_name                  = ""
         self.fund_deal_fee              = 0.0
@@ -62,17 +63,34 @@ class SIPPCompare(QMainWindow):
 
     # Get variables from platform editor input fields
     def init_variables(self):
-        self.plat_name                  = self.platform_win.get_plat_name()
-        self.fund_plat_fee              = self.platform_win.get_fund_plat_fee()
-        self.fund_deal_fee              = self.platform_win.get_fund_deal_fee()
-        self.share_plat_fee             = self.platform_win.get_share_plat_fee()
-        self.share_plat_max_fee         = self.platform_win.get_share_plat_max_fee()
-        self.share_deal_fee             = self.platform_win.get_share_deal_fee()
-        self.share_deal_reduce_trades   = self.platform_win.get_share_deal_reduce_trades()
-        self.share_deal_reduce_amount   = self.platform_win.get_share_deal_reduce_amount()
+        self.optional_boxes     = self.platform_win.get_optional_boxes()
+        self.fund_plat_fee      = self.platform_win.get_fund_plat_fee()
+        self.fund_deal_fee      = self.platform_win.get_fund_deal_fee()
+        self.share_plat_fee     = self.platform_win.get_share_plat_fee()
+        self.share_deal_fee     = self.platform_win.get_share_deal_fee()
+
+        # TODO: This is HORRIBLE - find better way of doing it! (maybe enums?)
+        if self.optional_boxes[0]:
+            self.plat_name = self.platform_win.get_plat_name()
+        else:
+            self.plat_name = None
+
+        if self.optional_boxes[1]:
+            self.share_plat_max_fee = self.platform_win.get_share_plat_max_fee()
+        else:
+            self.share_plat_max_fee = None
+
+        if self.optional_boxes[2]:
+            self.share_deal_reduce_trades = self.platform_win.get_share_deal_reduce_trades()
+        else:
+            self.share_deal_reduce_trades = None
+
+        if self.optional_boxes[3]:
+            self.share_deal_reduce_amount = self.platform_win.get_share_deal_reduce_amount()
+        else:
+            self.share_deal_reduce_amount = None
 
     # Calculate fees
-    # TODO: Error checking on combo boxes
     def calculate_fees(self):
         self.init_variables()
         # Set to zero each time to avoid persistence
@@ -98,13 +116,15 @@ class SIPPCompare(QMainWindow):
                 break
 
         shares_value = (1 - (slider_val / 100)) * value_num
-        if (self.share_plat_fee * shares_value / 12) > self.share_plat_max_fee:
+        if self.share_plat_max_fee is not None and \
+        (self.share_plat_fee * shares_value / 12) > self.share_plat_max_fee:
             self.share_plat_fees = self.share_plat_max_fee * 12
         else:
             self.share_plat_fees = self.share_plat_fee * shares_value
 
         share_trades_num = int(self.share_trades_combo.currentText())
-        if (share_trades_num / 12) >= self.share_deal_reduce_trades:
+        if self.share_deal_reduce_trades is not None and \
+        (share_trades_num / 12) >= self.share_deal_reduce_trades:
             self.share_deal_fees = self.share_deal_reduce_amount * share_trades_num
         else:
             self.share_deal_fees = self.share_deal_fee * share_trades_num
diff --git a/src/output_window.py b/src/output_window.py
index e9fcfb7..1765a51 100644
--- a/src/output_window.py
+++ b/src/output_window.py
@@ -23,7 +23,12 @@ class OutputWindow(QWidget):
         cur_time = datetime.datetime.now()
         if not os.path.exists("output"):
             os.makedirs("output")
-        filename_str = f"output/{self.platform_name}-{cur_time.year}.{cur_time.month}.{cur_time.day}.txt"
+        filename_str = f"output/"
+        if self.platform_name is not None:
+            filename_str += f"{self.platform_name}"
+        else:
+            filename_str += "Unnamed"
+        filename_str += f"-{cur_time.year}.{cur_time.month}.{cur_time.day}.txt"
         output_file = open(filename_str, "wt", encoding = "utf-8")
         output_file.write(self.results_str)
 
@@ -31,7 +36,10 @@ class OutputWindow(QWidget):
     def display_output(self, fund_plat_fees: float, fund_deal_fees: float,
                        share_plat_fees: float, share_deal_fees: float, plat_name: str):
         self.platform_name = plat_name
-        self.results_str = f"Fees breakdown (Platform \"{self.platform_name}\"):"
+        if self.platform_name is not None:
+            self.results_str = f"Fees breakdown (Platform \"{self.platform_name}\"):"
+        else:
+            self.results_str = f"Fees breakdown:"
 
         self.results_str += "\n\nPlatform fees:"
         # :.2f is used in order to display 2 decimal places (currency form)
diff --git a/src/platform_edit.py b/src/platform_edit.py
index 846551d..2c076ef 100644
--- a/src/platform_edit.py
+++ b/src/platform_edit.py
@@ -1,6 +1,6 @@
 from PyQt6.QtCore import QRegularExpression, QEvent, QObject, QTimer
 from PyQt6.QtGui import QRegularExpressionValidator
-from PyQt6.QtWidgets import QWidget, QLayout
+from PyQt6.QtWidgets import QWidget
 from PyQt6 import uic
 
 import main_window
@@ -13,6 +13,9 @@ class PlatformEdit(QWidget):
         uic.loadUi("gui/platform_edit.ui", self)
 
         # Initialise class variables
+        # Create main window object, passing this instance as param
+        self.main_win = main_window.SIPPCompare(self)
+
         # TODO: Make fund_plat_fee user-defined
         self.fund_plat_fee = [
             [0, 250000, 1000000, 2000000],
@@ -50,35 +53,42 @@ class PlatformEdit(QWidget):
             self.share_deal_reduce_amount_check
         ]
 
-        # Create main window object, passing this instance as param
-        self.main_win = main_window.SIPPCompare(self)
+        self.check_boxes_ticked = [
+            True,
+            False,
+            False,
+            False
+        ]
 
         # Handle events
-        # NOTE: Signal defined in UI file to close window when save button clicked
-        self.save_but.clicked.connect(self.init_variables)
-
         for field in self.required_fields:
             field.valueChanged.connect(self.check_valid)
+            field.installEventFilter(self)
 
         for field in self.optional_fields:
-            if field.staticMetaObject.className() == "QLineEdit":
+            field_type = field.staticMetaObject.className()
+            if field_type == "QLineEdit":
                 field.textChanged.connect(self.check_valid)
-            elif field.staticMetaObject.className() == "QDoubleSpinBox":
+            elif field_type == "QDoubleSpinBox" or field_type == "QSpinBox":
                 field.valueChanged.connect(self.check_valid)
+                field.installEventFilter(self)
 
         for check_box in self.optional_check_boxes:
             check_box.checkStateChanged.connect(self.check_valid)
 
+        # NOTE: Signal defined in UI file to close window when save button clicked
+        self.save_but.clicked.connect(self.init_variables)
+
         # Install event filter on input boxes in order to select all text on focus
+        # TODO: Seems like my eventFilter() override is capturing all events - need to stop this
+        """
         self.fund_deal_fee_box.installEventFilter(self)
         self.share_plat_fee_box.installEventFilter(self)
         self.share_plat_max_fee_box.installEventFilter(self)
         self.share_deal_fee_box.installEventFilter(self)
         self.share_deal_reduce_trades_box.installEventFilter(self)
         self.share_deal_reduce_amount_box.installEventFilter(self)
-
-        #for check_box in self.optional_check_boxes:
-        #    check_box.installEventFilter(self)
+        """
 
         # Set validators
         # Regex accepts any characters that match [a-Z], [0-9] or _
@@ -117,21 +127,34 @@ class PlatformEdit(QWidget):
             QTimer.singleShot(0, obj.selectAll)
         return False
 
-    # Check if all required fields have valid (non-zero) input
+    # This method does multiple things in order to validate the user's inputs:
+    # 1) Check all required fields have a non-zero value
+    # 2) If an optional checkbox is toggled: toggle editing of the corresponding field
+    # 3) Check all optional fields the user has picked have a non-zero value
+    # 4) If the above two conditions are met (1 & 3), make the 'Save' button clickable
+    # 5) Keep a record of which optional fields the user has chosen to fill in
+    # It's called when an optional check box emits a checkStateChanged() signal
+    # It's also called when any field emits a textChanged() or valueChanged() signal
     def check_valid(self):
         valid = True
 
+        # Check all required fields have a non-zero value
         for field in self.required_fields:
             if field.value() == 0:
                 valid = False
 
-        for check_box in self.optional_check_boxes:
-            check_box_pos = self.gridLayout.getItemPosition(self.gridLayout.indexOf(check_box))
+        for i in range(len(self.optional_check_boxes)):
+            # Find the coordinates of the input box corresponding to the checkbox
+            # It will be on the same row, in the column to the left (-1)
+            check_box_idx = self.gridLayout.indexOf(self.optional_check_boxes[i])
+            check_box_pos = self.gridLayout.getItemPosition(check_box_idx)
             input_box_pos = list(check_box_pos)[:2]
             input_box_pos[1] -= 1
+            # Return copy of input field widget from its coordinates
             input_box_item = self.gridLayout.itemAtPosition(input_box_pos[0], input_box_pos[1]).widget()
-            if check_box.isChecked():
+            if self.optional_check_boxes[i].isChecked():
                 input_box_item.setEnabled(True)
+                self.check_boxes_ticked[i] = True
                 input_box_type = input_box_item.staticMetaObject.className()
                 if input_box_type == "QLineEdit":
                     if input_box_item.text() == "":
@@ -141,6 +164,7 @@ class PlatformEdit(QWidget):
                         valid = False
             else:
                 input_box_item.setEnabled(False)
+                self.check_boxes_ticked[i] = False
 
         if valid:
             self.save_but.setEnabled(True)
@@ -148,6 +172,9 @@ class PlatformEdit(QWidget):
             self.save_but.setEnabled(False)
 
     # Getter functions (is this necessary? maybe directly reading class vars would be best...)
+    def get_optional_boxes(self):
+        return self.check_boxes_ticked
+
     def get_plat_name(self):
         return self.plat_name
 

From 107c388afba04721b7856a01548e4a6235458dc6 Mon Sep 17 00:00:00 2001
From: Roland W-H <r.weirhowell@gmail.com>
Date: Tue, 11 Feb 2025 19:04:21 +0000
Subject: [PATCH 5/8] add label hint for checkboxes, fix tab order

---
 gui/platform_edit.ui | 232 +++++++++++++++++++++----------------------
 1 file changed, 112 insertions(+), 120 deletions(-)

diff --git a/gui/platform_edit.ui b/gui/platform_edit.ui
index abd0088..446c309 100644
--- a/gui/platform_edit.ui
+++ b/gui/platform_edit.ui
@@ -6,20 +6,20 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>480</width>
-    <height>305</height>
+    <width>498</width>
+    <height>303</height>
    </rect>
   </property>
   <property name="minimumSize">
    <size>
-    <width>480</width>
-    <height>305</height>
+    <width>498</width>
+    <height>303</height>
    </size>
   </property>
   <property name="maximumSize">
    <size>
-    <width>480</width>
-    <height>305</height>
+    <width>498</width>
+    <height>303</height>
    </size>
   </property>
   <property name="windowTitle">
@@ -28,10 +28,10 @@
   <widget class="QWidget" name="gridLayoutWidget">
    <property name="geometry">
     <rect>
-     <x>10</x>
-     <y>10</y>
+     <x>20</x>
+     <y>20</y>
      <width>461</width>
-     <height>251</height>
+     <height>243</height>
     </rect>
    </property>
    <layout class="QGridLayout" name="gridLayout">
@@ -53,30 +53,24 @@
     <property name="verticalSpacing">
      <number>5</number>
     </property>
-    <item row="8" column="0" colspan="2">
-     <widget class="QLabel" name="share_deal_reduce_amount_lab">
-      <property name="text">
-       <string>Share dealing discount amount</string>
+    <item row="0" column="3">
+     <widget class="QCheckBox" name="plat_name_check">
+      <property name="checked">
+       <bool>true</bool>
       </property>
      </widget>
     </item>
-    <item row="8" column="2">
-     <widget class="QDoubleSpinBox" name="share_deal_reduce_amount_box">
+    <item row="6" column="3">
+     <widget class="QCheckBox" name="share_deal_fee_check">
       <property name="enabled">
        <bool>false</bool>
       </property>
-      <property name="buttonSymbols">
-       <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
-      </property>
-      <property name="correctionMode">
-       <enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
-      </property>
-      <property name="prefix">
-       <string>£</string>
+      <property name="checked">
+       <bool>true</bool>
       </property>
      </widget>
     </item>
-    <item row="4" column="2">
+    <item row="5" column="2">
      <widget class="QDoubleSpinBox" name="share_plat_max_fee_box">
       <property name="enabled">
        <bool>false</bool>
@@ -92,40 +86,17 @@
       </property>
      </widget>
     </item>
-    <item row="0" column="3">
-     <widget class="QCheckBox" name="plat_name_check">
-      <property name="text">
-       <string/>
-      </property>
-      <property name="checked">
-       <bool>true</bool>
-      </property>
-     </widget>
-    </item>
-    <item row="0" column="0" colspan="2">
-     <widget class="QLabel" name="plat_name_lab">
-      <property name="text">
-       <string>Platform name</string>
-      </property>
-     </widget>
-    </item>
-    <item row="0" column="2">
-     <widget class="QLineEdit" name="plat_name_box"/>
-    </item>
-    <item row="3" column="3">
-     <widget class="QCheckBox" name="share_plat_fee_check">
+    <item row="2" column="3">
+     <widget class="QCheckBox" name="fund_deal_fee_check">
       <property name="enabled">
        <bool>false</bool>
       </property>
-      <property name="text">
-       <string/>
-      </property>
       <property name="checked">
        <bool>true</bool>
       </property>
      </widget>
     </item>
-    <item row="5" column="2">
+    <item row="6" column="2">
      <widget class="QDoubleSpinBox" name="share_deal_fee_box">
       <property name="buttonSymbols">
        <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
@@ -138,7 +109,24 @@
       </property>
      </widget>
     </item>
-    <item row="1" column="2">
+    <item row="8" column="0" colspan="2">
+     <widget class="QLabel" name="share_deal_reduce_trades_lab">
+      <property name="text">
+       <string>Share dealing discount # of trades</string>
+      </property>
+     </widget>
+    </item>
+    <item row="9" column="3">
+     <widget class="QCheckBox" name="share_deal_reduce_amount_check"/>
+    </item>
+    <item row="5" column="0" colspan="2">
+     <widget class="QLabel" name="share_plat_max_fee_lab">
+      <property name="text">
+       <string>Share platform fee cap/mth</string>
+      </property>
+     </widget>
+    </item>
+    <item row="2" column="2">
      <widget class="QDoubleSpinBox" name="fund_deal_fee_box">
       <property name="buttonSymbols">
        <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
@@ -151,48 +139,14 @@
       </property>
      </widget>
     </item>
-    <item row="1" column="0" colspan="2">
-     <widget class="QLabel" name="fund_deal_fee_lab">
-      <property name="text">
-       <string>Fund dealing fee*</string>
-      </property>
-     </widget>
-    </item>
-    <item row="4" column="0" colspan="2">
-     <widget class="QLabel" name="share_plat_max_fee_lab">
-      <property name="text">
-       <string>Share platform fee cap/mth</string>
-      </property>
-     </widget>
-    </item>
-    <item row="3" column="2">
-     <widget class="QDoubleSpinBox" name="share_plat_fee_box">
-      <property name="buttonSymbols">
-       <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
-      </property>
-      <property name="correctionMode">
-       <enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
-      </property>
-      <property name="suffix">
-       <string>%</string>
-      </property>
-     </widget>
-    </item>
-    <item row="7" column="3">
-     <widget class="QCheckBox" name="share_deal_reduce_trades_check">
-      <property name="text">
-       <string/>
-      </property>
-     </widget>
-    </item>
-    <item row="5" column="0" colspan="2">
+    <item row="6" column="0" colspan="2">
      <widget class="QLabel" name="share_deal_fee_lab">
       <property name="text">
        <string>Share dealing fee*</string>
       </property>
      </widget>
     </item>
-    <item row="7" column="2">
+    <item row="8" column="2">
      <widget class="QSpinBox" name="share_deal_reduce_trades_box">
       <property name="enabled">
        <bool>false</bool>
@@ -205,57 +159,79 @@
       </property>
      </widget>
     </item>
-    <item row="7" column="0" colspan="2">
-     <widget class="QLabel" name="share_deal_reduce_trades_lab">
-      <property name="text">
-       <string>Share dealing discount # of trades</string>
-      </property>
-     </widget>
-    </item>
     <item row="8" column="3">
-     <widget class="QCheckBox" name="share_deal_reduce_amount_check">
-      <property name="text">
-       <string/>
-      </property>
-     </widget>
+     <widget class="QCheckBox" name="share_deal_reduce_trades_check"/>
     </item>
-    <item row="5" column="3">
-     <widget class="QCheckBox" name="share_deal_fee_check">
+    <item row="4" column="3">
+     <widget class="QCheckBox" name="share_plat_fee_check">
       <property name="enabled">
        <bool>false</bool>
       </property>
-      <property name="text">
-       <string/>
-      </property>
       <property name="checked">
        <bool>true</bool>
       </property>
      </widget>
     </item>
-    <item row="3" column="0" colspan="2">
+    <item row="2" column="0" colspan="2">
+     <widget class="QLabel" name="fund_deal_fee_lab">
+      <property name="text">
+       <string>Fund dealing fee*</string>
+      </property>
+     </widget>
+    </item>
+    <item row="5" column="3">
+     <widget class="QCheckBox" name="share_plat_max_fee_check"/>
+    </item>
+    <item row="0" column="2">
+     <widget class="QLineEdit" name="plat_name_box"/>
+    </item>
+    <item row="9" column="0" colspan="2">
+     <widget class="QLabel" name="share_deal_reduce_amount_lab">
+      <property name="text">
+       <string>Share dealing discount amount</string>
+      </property>
+     </widget>
+    </item>
+    <item row="4" column="0" colspan="2">
      <widget class="QLabel" name="share_plat_fee_lab">
       <property name="text">
        <string>Share platform fee*</string>
       </property>
      </widget>
     </item>
-    <item row="1" column="3">
-     <widget class="QCheckBox" name="fund_deal_fee_check">
-      <property name="enabled">
-       <bool>false</bool>
+    <item row="4" column="2">
+     <widget class="QDoubleSpinBox" name="share_plat_fee_box">
+      <property name="buttonSymbols">
+       <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
       </property>
-      <property name="text">
-       <string/>
+      <property name="correctionMode">
+       <enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
       </property>
-      <property name="checked">
-       <bool>true</bool>
+      <property name="suffix">
+       <string>%</string>
       </property>
      </widget>
     </item>
-    <item row="4" column="3">
-     <widget class="QCheckBox" name="share_plat_max_fee_check">
+    <item row="0" column="0" colspan="2">
+     <widget class="QLabel" name="plat_name_lab">
       <property name="text">
-       <string/>
+       <string>Platform name</string>
+      </property>
+     </widget>
+    </item>
+    <item row="9" column="2">
+     <widget class="QDoubleSpinBox" name="share_deal_reduce_amount_box">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
+      <property name="buttonSymbols">
+       <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
+      </property>
+      <property name="correctionMode">
+       <enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
+      </property>
+      <property name="prefix">
+       <string>£</string>
       </property>
      </widget>
     </item>
@@ -267,7 +243,7 @@
    </property>
    <property name="geometry">
     <rect>
-     <x>330</x>
+     <x>350</x>
      <y>270</y>
      <width>141</width>
      <height>24</height>
@@ -277,11 +253,11 @@
     <string>Save</string>
    </property>
   </widget>
-  <widget class="QLabel" name="label">
+  <widget class="QLabel" name="req_field_lab">
    <property name="geometry">
     <rect>
-     <x>20</x>
-     <y>270</y>
+     <x>10</x>
+     <y>280</y>
      <width>191</width>
      <height>21</height>
     </rect>
@@ -290,6 +266,22 @@
     <string>* Indicates required field</string>
    </property>
   </widget>
+  <widget class="QLabel" name="active_lab">
+   <property name="geometry">
+    <rect>
+     <x>437</x>
+     <y>10</y>
+     <width>61</width>
+     <height>16</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Active?</string>
+   </property>
+   <property name="alignment">
+    <set>Qt::AlignmentFlag::AlignCenter</set>
+   </property>
+  </widget>
  </widget>
  <tabstops>
   <tabstop>plat_name_box</tabstop>

From 9ef60486019ff4d568111b83cdc692ec90633d5f Mon Sep 17 00:00:00 2001
From: Roland W-H <r.weirhowell@gmail.com>
Date: Tue, 11 Feb 2025 19:31:13 +0000
Subject: [PATCH 6/8] do input validation on pension value field

---
 src/main_window.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/main_window.py b/src/main_window.py
index a012427..093e511 100644
--- a/src/main_window.py
+++ b/src/main_window.py
@@ -40,7 +40,7 @@ class SIPPCompare(QMainWindow):
         self.actionEdit_Platforms.triggered.connect(self.show_platform_edit)
         # Update percentage mix label when slider moved
         self.mix_slider.valueChanged.connect(self.update_slider_lab)
-        #self.value_input.valueChanged.connect(self.check_valid)
+        self.value_input.valueChanged.connect(self.check_valid)
         self.share_trades_combo.currentTextChanged.connect(self.check_valid)
         self.fund_trades_combo.currentTextChanged.connect(self.check_valid)
 
@@ -56,7 +56,8 @@ class SIPPCompare(QMainWindow):
 
     def check_valid(self):
         if self.share_trades_combo.currentText() != "" \
-        and self.fund_trades_combo.currentText() != "":
+        and self.fund_trades_combo.currentText() != "" \
+        and self.value_input.value() != 0:
             self.calc_but.setEnabled(True)
         else:
             self.calc_but.setEnabled(False)

From 68ac9924836c5cad29ee74ab13a423b40ae63cb0 Mon Sep 17 00:00:00 2001
From: Roland W-H <r.weirhowell@gmail.com>
Date: Tue, 11 Feb 2025 21:19:05 +0000
Subject: [PATCH 7/8] implement custom Q(Double)SpinBox widget for onFocus
 selection

---
 gui/platform_edit.ui            | 26 +++++++++++++++++++-------
 src/platform_edit.py            | 20 +++++---------------
 src/widgets/fastedit_spinbox.py | 13 +++++++++++++
 3 files changed, 37 insertions(+), 22 deletions(-)
 create mode 100644 src/widgets/fastedit_spinbox.py

diff --git a/gui/platform_edit.ui b/gui/platform_edit.ui
index 446c309..9302c89 100644
--- a/gui/platform_edit.ui
+++ b/gui/platform_edit.ui
@@ -71,7 +71,7 @@
      </widget>
     </item>
     <item row="5" column="2">
-     <widget class="QDoubleSpinBox" name="share_plat_max_fee_box">
+     <widget class="FastEditQDoubleSpinBox" name="share_plat_max_fee_box">
       <property name="enabled">
        <bool>false</bool>
       </property>
@@ -97,7 +97,7 @@
      </widget>
     </item>
     <item row="6" column="2">
-     <widget class="QDoubleSpinBox" name="share_deal_fee_box">
+     <widget class="FastEditQDoubleSpinBox" name="share_deal_fee_box">
       <property name="buttonSymbols">
        <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
       </property>
@@ -122,12 +122,12 @@
     <item row="5" column="0" colspan="2">
      <widget class="QLabel" name="share_plat_max_fee_lab">
       <property name="text">
-       <string>Share platform fee cap/mth</string>
+       <string>Share platform monthly fee cap</string>
       </property>
      </widget>
     </item>
     <item row="2" column="2">
-     <widget class="QDoubleSpinBox" name="fund_deal_fee_box">
+     <widget class="FastEditQDoubleSpinBox" name="fund_deal_fee_box">
       <property name="buttonSymbols">
        <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
       </property>
@@ -147,7 +147,7 @@
      </widget>
     </item>
     <item row="8" column="2">
-     <widget class="QSpinBox" name="share_deal_reduce_trades_box">
+     <widget class="FastEditQSpinBox" name="share_deal_reduce_trades_box">
       <property name="enabled">
        <bool>false</bool>
       </property>
@@ -200,7 +200,7 @@
      </widget>
     </item>
     <item row="4" column="2">
-     <widget class="QDoubleSpinBox" name="share_plat_fee_box">
+     <widget class="FastEditQDoubleSpinBox" name="share_plat_fee_box">
       <property name="buttonSymbols">
        <enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
       </property>
@@ -220,7 +220,7 @@
      </widget>
     </item>
     <item row="9" column="2">
-     <widget class="QDoubleSpinBox" name="share_deal_reduce_amount_box">
+     <widget class="FastEditQDoubleSpinBox" name="share_deal_reduce_amount_box">
       <property name="enabled">
        <bool>false</bool>
       </property>
@@ -283,6 +283,18 @@
    </property>
   </widget>
  </widget>
+ <customwidgets>
+  <customwidget>
+   <class>FastEditQDoubleSpinBox</class>
+   <extends>QDoubleSpinBox</extends>
+   <header>widgets/fastedit_spinbox</header>
+  </customwidget>
+  <customwidget>
+   <class>FastEditQSpinBox</class>
+   <extends>QSpinBox</extends>
+   <header>widgets/fastedit_spinbox</header>
+  </customwidget>
+ </customwidgets>
  <tabstops>
   <tabstop>plat_name_box</tabstop>
   <tabstop>fund_deal_fee_box</tabstop>
diff --git a/src/platform_edit.py b/src/platform_edit.py
index 2c076ef..c3b7298 100644
--- a/src/platform_edit.py
+++ b/src/platform_edit.py
@@ -1,6 +1,6 @@
 from PyQt6.QtCore import QRegularExpression, QEvent, QObject, QTimer
 from PyQt6.QtGui import QRegularExpressionValidator
-from PyQt6.QtWidgets import QWidget
+from PyQt6.QtWidgets import QWidget, QDoubleSpinBox
 from PyQt6 import uic
 
 import main_window
@@ -79,17 +79,6 @@ class PlatformEdit(QWidget):
         # NOTE: Signal defined in UI file to close window when save button clicked
         self.save_but.clicked.connect(self.init_variables)
 
-        # Install event filter on input boxes in order to select all text on focus
-        # TODO: Seems like my eventFilter() override is capturing all events - need to stop this
-        """
-        self.fund_deal_fee_box.installEventFilter(self)
-        self.share_plat_fee_box.installEventFilter(self)
-        self.share_plat_max_fee_box.installEventFilter(self)
-        self.share_deal_fee_box.installEventFilter(self)
-        self.share_deal_reduce_trades_box.installEventFilter(self)
-        self.share_deal_reduce_amount_box.installEventFilter(self)
-        """
-
         # Set validators
         # Regex accepts any characters that match [a-Z], [0-9] or _
         self.plat_name_box.setValidator(
@@ -120,11 +109,12 @@ class PlatformEdit(QWidget):
         self.main_win.show()
 
     # When focus is given to an input box, select all text in it (easier to edit)
-    def eventFilter(self, obj: QObject, event: QEvent):
-        if event.type() == QEvent.Type.FocusIn:
+    def focusInEvent(self, event):
+        print("yay")
+        if event.gotFocus():
             # Alternative condition for % suffix - currently unused
             #if obj.value() == 0 or obj == self.share_plat_fee_box:
-            QTimer.singleShot(0, obj.selectAll)
+            QTimer.singleShot(0, sender.selectAll)
         return False
 
     # This method does multiple things in order to validate the user's inputs:
diff --git a/src/widgets/fastedit_spinbox.py b/src/widgets/fastedit_spinbox.py
new file mode 100644
index 0000000..dcdc692
--- /dev/null
+++ b/src/widgets/fastedit_spinbox.py
@@ -0,0 +1,13 @@
+from PyQt6.QtCore import QTimer
+from PyQt6.QtWidgets import QSpinBox, QDoubleSpinBox
+
+
+class FastEditQDoubleSpinBox(QDoubleSpinBox):
+    def focusInEvent(self, e):
+        QTimer.singleShot(0, self.selectAll)
+        super(FastEditQDoubleSpinBox, self).focusInEvent(e)
+
+class FastEditQSpinBox(QSpinBox):
+    def focusInEvent(self, e):
+        QTimer.singleShot(0, self.selectAll)
+        super(FastEditQSpinBox, self).focusInEvent(e)

From 679a509101ea249e20601353b4804718f8de68af Mon Sep 17 00:00:00 2001
From: Roland W-H <r.weirhowell@gmail.com>
Date: Mon, 17 Feb 2025 10:05:38 +0000
Subject: [PATCH 8/8] fix input validation to work with custom widgets

---
 gui/platform_edit.ui | 18 ++++++++++++++++++
 src/platform_edit.py | 19 ++++---------------
 2 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/gui/platform_edit.ui b/gui/platform_edit.ui
index 9302c89..ddf9a0e 100644
--- a/gui/platform_edit.ui
+++ b/gui/platform_edit.ui
@@ -84,6 +84,9 @@
       <property name="prefix">
        <string>£</string>
       </property>
+      <property name="maximum">
+       <double>999.000000000000000</double>
+      </property>
      </widget>
     </item>
     <item row="2" column="3">
@@ -107,6 +110,9 @@
       <property name="prefix">
        <string>£</string>
       </property>
+      <property name="maximum">
+       <double>999.000000000000000</double>
+      </property>
      </widget>
     </item>
     <item row="8" column="0" colspan="2">
@@ -137,6 +143,9 @@
       <property name="prefix">
        <string>£</string>
       </property>
+      <property name="maximum">
+       <double>999.000000000000000</double>
+      </property>
      </widget>
     </item>
     <item row="6" column="0" colspan="2">
@@ -157,6 +166,9 @@
       <property name="correctionMode">
        <enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
       </property>
+      <property name="maximum">
+       <number>999</number>
+      </property>
      </widget>
     </item>
     <item row="8" column="3">
@@ -210,6 +222,9 @@
       <property name="suffix">
        <string>%</string>
       </property>
+      <property name="maximum">
+       <double>99.000000000000000</double>
+      </property>
      </widget>
     </item>
     <item row="0" column="0" colspan="2">
@@ -233,6 +248,9 @@
       <property name="prefix">
        <string>£</string>
       </property>
+      <property name="maximum">
+       <double>999.000000000000000</double>
+      </property>
      </widget>
     </item>
    </layout>
diff --git a/src/platform_edit.py b/src/platform_edit.py
index c3b7298..55f4e4a 100644
--- a/src/platform_edit.py
+++ b/src/platform_edit.py
@@ -1,6 +1,6 @@
-from PyQt6.QtCore import QRegularExpression, QEvent, QObject, QTimer
+from PyQt6.QtCore import QRegularExpression
 from PyQt6.QtGui import QRegularExpressionValidator
-from PyQt6.QtWidgets import QWidget, QDoubleSpinBox
+from PyQt6.QtWidgets import QWidget
 from PyQt6 import uic
 
 import main_window
@@ -63,15 +63,13 @@ class PlatformEdit(QWidget):
         # Handle events
         for field in self.required_fields:
             field.valueChanged.connect(self.check_valid)
-            field.installEventFilter(self)
 
         for field in self.optional_fields:
             field_type = field.staticMetaObject.className()
             if field_type == "QLineEdit":
                 field.textChanged.connect(self.check_valid)
-            elif field_type == "QDoubleSpinBox" or field_type == "QSpinBox":
+            elif field_type == "FastEditQDoubleSpinBox" or field_type == "FastEditQSpinBox":
                 field.valueChanged.connect(self.check_valid)
-                field.installEventFilter(self)
 
         for check_box in self.optional_check_boxes:
             check_box.checkStateChanged.connect(self.check_valid)
@@ -108,15 +106,6 @@ class PlatformEdit(QWidget):
         # Once user input is received show main window
         self.main_win.show()
 
-    # When focus is given to an input box, select all text in it (easier to edit)
-    def focusInEvent(self, event):
-        print("yay")
-        if event.gotFocus():
-            # Alternative condition for % suffix - currently unused
-            #if obj.value() == 0 or obj == self.share_plat_fee_box:
-            QTimer.singleShot(0, sender.selectAll)
-        return False
-
     # This method does multiple things in order to validate the user's inputs:
     # 1) Check all required fields have a non-zero value
     # 2) If an optional checkbox is toggled: toggle editing of the corresponding field
@@ -149,7 +138,7 @@ class PlatformEdit(QWidget):
                 if input_box_type == "QLineEdit":
                     if input_box_item.text() == "":
                         valid = False
-                elif input_box_type == "QDoubleSpinBox" or input_box_type == "QSpinBox":
+                elif input_box_type == "FastEditQDoubleSpinBox" or input_box_type == "FastEditQSpinBox":
                     if input_box_item.value() == 0:
                         valid = False
             else: