refactor: Splitting Classes into Separate Files
This commit is contained in:
parent
ce2dd90a39
commit
17f08bc74f
6 changed files with 568 additions and 517 deletions
|
@ -1,11 +1,16 @@
|
|||
# Changelog
|
||||
|
||||
### 1.2.x: Refactor
|
||||
#### 1.2.0: Splitting Classes into Separate Files
|
||||
- Refactored `gui.py`, which previously contained almost all the code, into multiple files.
|
||||
- Each window's logic is now in its own file, improving code organization.
|
||||
- Window layouts remain in `.ui` folder, while their logic is now properly separated.
|
||||
|
||||
## 1.1.x
|
||||
### 1.1.0: New Function in Preview Window
|
||||
- Added a new feature to the preview window: **Hold a button to temporarily view the original (unedited) image.** This makes it easier to compare changes.
|
||||
- Minor UI adjustments.
|
||||
|
||||
|
||||
## 1.0.x
|
||||
### 1.0.1: Fixed spelling
|
||||
- Fixes spelling some places
|
||||
|
|
6
TODO.md
6
TODO.md
|
@ -1,6 +0,0 @@
|
|||
# TODO
|
||||
|
||||
## Improvments
|
||||
### Preview window
|
||||
Improve performence by changing when the images is updated.
|
||||
Right now, when moving the slider, the image gets updated for every single step increase resulting in lagging
|
|
@ -1,4 +1,30 @@
|
|||
from .gui import main
|
||||
import sys
|
||||
from PySide6 import QtWidgets
|
||||
from .utils.utility import Utilities
|
||||
from .mainWindow import OptimaLab35
|
||||
from .const import (
|
||||
CONFIG_BASE_PATH
|
||||
)
|
||||
|
||||
def main():
|
||||
u = Utilities(CONFIG_BASE_PATH)
|
||||
app_settings = u.load_settings()
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
|
||||
try:
|
||||
import qdarktheme
|
||||
app_settings["theme"]["theme_pkg"] = True
|
||||
except ImportError:
|
||||
app_settings["theme"]["theme_pkg"] = False
|
||||
|
||||
if app_settings["theme"]["use_custom_theme"] and app_settings["theme"]["theme_pkg"]:
|
||||
qdarktheme.setup_theme(app_settings["theme"]["mode"].lower())
|
||||
|
||||
u.save_settings(app_settings)
|
||||
|
||||
window = OptimaLab35()
|
||||
window.show()
|
||||
app.exec()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
import sys
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
from .ui import resources_rc
|
||||
from PyPiUpdater import PyPiUpdater
|
||||
from optima35.core import OptimaManager
|
||||
|
||||
from .utils.utility import Utilities
|
||||
from .ui.main_window import Ui_MainWindow
|
||||
from .ui.preview_window import Ui_Preview_Window
|
||||
from .ui.settings_window import Ui_Settings_Window
|
||||
from .ui.exif_handler_window import ExifEditor
|
||||
from .ui.simple_dialog import SimpleDialog # Import the SimpleDialog class
|
||||
from OptimaLab35 import __version__
|
||||
from .const import (
|
||||
APPLICATION_NAME,
|
||||
CONFIG_BASE_PATH
|
||||
)
|
||||
|
||||
from .ui import resources_rc
|
||||
from .previewWindow import PreviewWindow
|
||||
from .settingsWindow import SettingsWindow
|
||||
|
||||
from .utils.utility import Utilities
|
||||
from .ui.main_window import Ui_MainWindow
|
||||
from .ui.exif_handler_window import ExifEditor
|
||||
from .ui.simple_dialog import SimpleDialog # Import the SimpleDialog class
|
||||
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
|
||||
from PySide6.QtCore import (
|
||||
|
@ -26,9 +25,7 @@ from PySide6.QtCore import (
|
|||
Signal,
|
||||
QObject,
|
||||
QRegularExpression,
|
||||
Qt,
|
||||
QTimer,
|
||||
Slot
|
||||
Qt
|
||||
)
|
||||
|
||||
from PySide6.QtWidgets import (
|
||||
|
@ -38,7 +35,7 @@ from PySide6.QtWidgets import (
|
|||
QFileDialog
|
||||
)
|
||||
|
||||
from PySide6.QtGui import QPixmap, QRegularExpressionValidator, QIcon
|
||||
from PySide6.QtGui import QRegularExpressionValidator, QIcon
|
||||
|
||||
class OptimaLab35(QMainWindow, Ui_MainWindow):
|
||||
def __init__(self):
|
||||
|
@ -99,8 +96,6 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
|
|||
validator = QRegularExpressionValidator(regex)
|
||||
self.ui.lat_lineEdit.setValidator(validator)
|
||||
self.ui.long_lineEdit.setValidator(validator)
|
||||
#layout.addWidget(self.ui.lat_lineEdit)
|
||||
#layout.addWidget(self.ui.long_lineEdit)
|
||||
|
||||
# UI related function, changing parts, open, etc.
|
||||
def open_preview_window(self):
|
||||
|
@ -501,441 +496,6 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
|
|||
QApplication.closeAllWindows()
|
||||
event.accept()
|
||||
|
||||
class SettingsWindow(QMainWindow, Ui_Settings_Window):
|
||||
# Mixture of code by me, code/functions refactored by ChatGPT and code directly from ChatGPT
|
||||
def __init__(self, optimalab35_localversion, optima35_localversion):
|
||||
super(SettingsWindow, self).__init__()
|
||||
self.ui = Ui_Settings_Window()
|
||||
self.ui.setupUi(self)
|
||||
self.u = Utilities(os.path.expanduser("~/.config/OptimaLab35"))
|
||||
self.app_settings = self.u.load_settings()
|
||||
self.dev_mode = True if optimalab35_localversion == "0.0.1" else False
|
||||
from PyPiUpdater import PyPiUpdater
|
||||
# Update log file location
|
||||
self.update_log_file = os.path.expanduser("~/.config/OptimaLab35/update_log.json")
|
||||
# Store local versions
|
||||
self.optimalab35_localversion = optimalab35_localversion
|
||||
self.optima35_localversion = optima35_localversion
|
||||
|
||||
# Create PyPiUpdater instances
|
||||
self.ppu_ol35 = PyPiUpdater("OptimaLab35", self.optimalab35_localversion, self.update_log_file)
|
||||
self.ppu_o35 = PyPiUpdater("optima35", self.optima35_localversion, self.update_log_file)
|
||||
self.ol35_last_state = self.ppu_ol35.get_last_state()
|
||||
self.o35_last_state = self.ppu_o35.get_last_state()
|
||||
|
||||
# Track which packages need an update
|
||||
self.updates_available = {"OptimaLab35": False, "optima35": False}
|
||||
|
||||
self.define_gui_interaction()
|
||||
|
||||
def define_gui_interaction(self):
|
||||
"""Setup UI interactions."""
|
||||
# Updater related
|
||||
self.ui.label_optimalab35_localversion.setText(self.optimalab35_localversion)
|
||||
self.ui.label_optima35_localversion.setText(self.optima35_localversion)
|
||||
|
||||
self.ui.label_latest_version.setText("Latest version")
|
||||
self.ui.label_optimalab35_latestversion.setText("...")
|
||||
self.ui.label_optima35_latestversion.setText("...")
|
||||
|
||||
self.ui.update_and_restart_Button.setEnabled(False)
|
||||
|
||||
# Connect buttons to functions
|
||||
self.ui.check_for_update_Button.clicked.connect(self.check_for_updates)
|
||||
self.ui.update_and_restart_Button.clicked.connect(self.update_and_restart)
|
||||
self.ui.label_last_check.setText(f"Last check: {self.time_to_string(self.ol35_last_state[0])}")
|
||||
self.ui.dev_widget.setVisible(False)
|
||||
|
||||
# Timer for long press detection
|
||||
self.timer = QTimer()
|
||||
self.timer.setSingleShot(True)
|
||||
self.timer.timeout.connect(self.toggle_dev_ui)
|
||||
|
||||
# Connect button press/release
|
||||
self.ui.check_for_update_Button.pressed.connect(self.start_long_press)
|
||||
self.ui.check_for_update_Button.released.connect(self.cancel_long_press)
|
||||
self.ui.label_5.setText('<li><a href="https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/blob/main/CHANGELOG.md?ref_type=heads">Changelog</a></li>')
|
||||
self.ui.label_5.setOpenExternalLinks(True)
|
||||
#settings related
|
||||
self.load_settings_into_ui()
|
||||
self.ui.reset_exif_Button.clicked.connect(self.ask_reset_exif)
|
||||
self.ui.save_and_close_Button.clicked.connect(self.save_and_close)
|
||||
self.ui.save_and_restart_Button.clicked.connect(self.save_and_restart)
|
||||
|
||||
if os.name == "nt": # Disable restart app when windows.
|
||||
self.ui.save_and_restart_Button.setVisible(False)
|
||||
self.ui.restart_checkBox.setChecked(False)
|
||||
self.ui.restart_checkBox.setVisible(False)
|
||||
|
||||
# setting related
|
||||
|
||||
def load_settings_into_ui(self):
|
||||
"""Loads the settings into the UI elements."""
|
||||
settings = self.app_settings
|
||||
theme_mode = settings["theme"]["mode"]
|
||||
use_custom_theme = settings["theme"]["use_custom_theme"]
|
||||
pkg_available = settings["theme"]["theme_pkg"]
|
||||
|
||||
if pkg_available:
|
||||
index = self.ui.theme_selection_comboBox.findText(theme_mode, QtCore.Qt.MatchFlag.MatchExactly)
|
||||
if index != -1:
|
||||
self.ui.theme_selection_comboBox.setCurrentIndex(index)
|
||||
self.ui.enable_theme_checkBox.setChecked(use_custom_theme)
|
||||
self.ui.install_pkg_Button.setVisible(False)
|
||||
self.ui.enable_theme_checkBox.setEnabled(True)
|
||||
else:
|
||||
self.ui.enable_theme_checkBox.setEnabled(False)
|
||||
self.ui.install_pkg_Button.clicked.connect(self.install_theme_pkg)
|
||||
|
||||
|
||||
def install_theme_pkg(self):
|
||||
a = self.ppu_ol35.install_package("PyQtDarkTheme-fork")
|
||||
self.ui.install_pkg_Button.setEnabled(False)
|
||||
self.ui.install_pkg_Button.setText("Please wait...")
|
||||
|
||||
msg_box = QMessageBox()
|
||||
msg_box.setIcon(QMessageBox.Information)
|
||||
msg_box.setWindowTitle("Message")
|
||||
msg_box.setText(a[1])
|
||||
msg_box.setStandardButtons(QMessageBox.Ok)
|
||||
msg_box.exec()
|
||||
if a[0]:
|
||||
self.app_settings["theme"]["theme_pkg"] = True
|
||||
self.load_settings_into_ui()
|
||||
else:
|
||||
self.ui.install_pkg_Button.setEnabled(True)
|
||||
self.ui.install_pkg_Button.setText("Try again?")
|
||||
|
||||
def save_settings(self):
|
||||
self.app_settings["theme"]["mode"] = self.ui.theme_selection_comboBox.currentText()
|
||||
self.app_settings["theme"]["use_custom_theme"] = self.ui.enable_theme_checkBox.isChecked()
|
||||
self.u.save_settings(self.app_settings)
|
||||
|
||||
def save_and_close(self):
|
||||
self.save_settings()
|
||||
self.close()
|
||||
|
||||
def save_and_restart(self):
|
||||
msg = QMessageBox()
|
||||
msg.setIcon(QMessageBox.Icon.Question)
|
||||
msg.setWindowTitle("Confirm Reset")
|
||||
msg.setText("Are you sure you want to restart the app?")
|
||||
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
||||
|
||||
# Show the message box and wait for the user's response
|
||||
response = msg.exec()
|
||||
|
||||
# Check response and perform action
|
||||
if response == QMessageBox.StandardButton.Yes:
|
||||
self.save_settings()
|
||||
self.restart_program()
|
||||
else:
|
||||
pass # Do nothing if "No" is selected
|
||||
|
||||
def ask_reset_exif(self):
|
||||
"""Shows a dialog to ask the user if they are sure about resetting EXIF options to default."""
|
||||
# Create a QMessageBox with a Yes/No question
|
||||
msg = QMessageBox()
|
||||
msg.setIcon(QMessageBox.Icon.Question)
|
||||
msg.setWindowTitle("Confirm Reset")
|
||||
msg.setText("Are you sure you want to reset the EXIF options to default?")
|
||||
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
||||
|
||||
# Show the message box and wait for the user's response
|
||||
response = msg.exec()
|
||||
|
||||
# Check response and perform action
|
||||
if response == QMessageBox.StandardButton.Yes:
|
||||
self.u.default_exif() # Reset EXIF options to default
|
||||
else:
|
||||
pass # Do nothing if "No" is selected
|
||||
|
||||
# update related parts
|
||||
def start_long_press(self):
|
||||
"""Start the timer when button is pressed."""
|
||||
# brave AI
|
||||
self.timer.start(1000) # 1-second long press
|
||||
|
||||
def cancel_long_press(self):
|
||||
"""Cancel long press if released early."""
|
||||
# brave AI
|
||||
self.timer.stop()
|
||||
|
||||
def toggle_dev_ui(self):
|
||||
"""Show or hide the hidden UI when long press is detected."""
|
||||
self.ui.dev_widget.setVisible(True)
|
||||
|
||||
self.ui.check_local_Button.clicked.connect(self.local_check_for_updates)
|
||||
self.ui.update_local_Button.clicked.connect(self.local_update)
|
||||
|
||||
def local_check_for_updates(self):
|
||||
dist_folder = os.path.expanduser("~/.config/OptimaLab35/dist/")
|
||||
self.ui.label_optimalab35_latestversion.setText("Checking...")
|
||||
self.ui.label_optima35_latestversion.setText("Checking...")
|
||||
|
||||
# Check OptimaLab35 update
|
||||
ol35_pkg_info = self.ppu_ol35.check_update_local(dist_folder)
|
||||
if ol35_pkg_info[0] is None:
|
||||
self.ui.label_optimalab35_latestversion.setText(ol35_pkg_info[1][0:13])
|
||||
else:
|
||||
self.ui.label_optimalab35_latestversion.setText(ol35_pkg_info[1])
|
||||
self.updates_available["OptimaLab35"] = ol35_pkg_info[0]
|
||||
|
||||
# Check optima35 update
|
||||
o35_pkg_info = self.ppu_o35.check_update_local(dist_folder)
|
||||
if o35_pkg_info[0] is None:
|
||||
self.ui.label_optima35_latestversion.setText(o35_pkg_info[1][0:13])
|
||||
else:
|
||||
self.ui.label_optima35_latestversion.setText(o35_pkg_info[1])
|
||||
self.updates_available["optima35"] = o35_pkg_info[0]
|
||||
|
||||
def local_update(self):
|
||||
dist_folder = os.path.expanduser("~/.config/OptimaLab35/dist/")
|
||||
packages_to_update = [pkg for pkg, update in self.updates_available.items() if update]
|
||||
|
||||
if not packages_to_update:
|
||||
QMessageBox.information(self, "Update", "No updates available.")
|
||||
return
|
||||
|
||||
# Confirm update
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Update Available")
|
||||
message = f"Updating: {', '.join(packages_to_update)}\nUpdate "
|
||||
|
||||
if self.ui.restart_checkBox.isChecked():
|
||||
message = message + "and restart app?"
|
||||
else:
|
||||
message = message + "app?"
|
||||
|
||||
msg.setText(message)
|
||||
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
||||
result = msg.exec()
|
||||
|
||||
if result == QMessageBox.Yes:
|
||||
update_results = [] # Store results
|
||||
|
||||
for package in packages_to_update:
|
||||
if package == "OptimaLab35":
|
||||
pkg_info = self.ppu_ol35.update_from_local(dist_folder)
|
||||
elif package == "optima35":
|
||||
pkg_info = self.ppu_o35.update_from_local(dist_folder)
|
||||
|
||||
update_results.append(f"{package}: {'Success' if pkg_info[0] else 'Failed'}\n{pkg_info[1]}")
|
||||
|
||||
# Show summary of updates
|
||||
# Show update completion message
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Update Complete")
|
||||
msg.setText("\n\n".join(update_results))
|
||||
msg.setStandardButtons(QMessageBox.Ok)
|
||||
msg.exec()
|
||||
|
||||
# Restart the application after user clicks "OK"
|
||||
if self.ui.restart_checkBox.isChecked():
|
||||
self.restart_program()
|
||||
|
||||
def time_to_string(self, time_time):
|
||||
try:
|
||||
dt_obj = datetime.fromtimestamp(time_time)
|
||||
date_string = dt_obj.strftime("%d %h %H:%M")
|
||||
return date_string
|
||||
except TypeError:
|
||||
return "Missing information"
|
||||
|
||||
def check_for_updates(self):
|
||||
"""Check for updates and update the UI."""
|
||||
self.ui.check_for_update_Button.setEnabled(False)
|
||||
self.ui.label_optimalab35_latestversion.setText("Checking...")
|
||||
self.ui.label_optima35_latestversion.setText("Checking...")
|
||||
|
||||
# Check OptimaLab35 update
|
||||
ol35_pkg_info = self.ppu_ol35.check_for_update()
|
||||
if ol35_pkg_info[0] is None:
|
||||
self.ui.label_optimalab35_latestversion.setText(ol35_pkg_info[1][0:13])
|
||||
else:
|
||||
self.ui.label_optimalab35_latestversion.setText(ol35_pkg_info[1])
|
||||
self.updates_available["OptimaLab35"] = ol35_pkg_info[0]
|
||||
|
||||
# Check optima35 update
|
||||
o35_pkg_info = self.ppu_o35.check_for_update()
|
||||
if o35_pkg_info[0] is None:
|
||||
self.ui.label_optima35_latestversion.setText(o35_pkg_info[1][0:13])
|
||||
else:
|
||||
self.ui.label_optima35_latestversion.setText(o35_pkg_info[1])
|
||||
self.updates_available["optima35"] = o35_pkg_info[0]
|
||||
|
||||
# Enable update button if any update is available
|
||||
if any(self.updates_available.values()):
|
||||
if self.dev_mode:
|
||||
self.ui.update_and_restart_Button.setEnabled(False)
|
||||
self.ui.update_and_restart_Button.setText("Update disabled")
|
||||
else:
|
||||
self.ui.update_and_restart_Button.setEnabled(True)
|
||||
|
||||
last_date = self.time_to_string(self.ppu_ol35.get_last_state()[0])
|
||||
self.ui.label_last_check.setText(f"Last check: {last_date}")
|
||||
self.ui.label_latest_version.setText("Online version")
|
||||
self.ui.check_for_update_Button.setEnabled(True)
|
||||
|
||||
def update_and_restart(self):
|
||||
"""Update selected packages and restart the application."""
|
||||
packages_to_update = [pkg for pkg, update in self.updates_available.items() if update]
|
||||
|
||||
if not packages_to_update:
|
||||
QMessageBox.information(self, "Update", "No updates available.")
|
||||
return
|
||||
|
||||
# Confirm update
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Update Available")
|
||||
message = f"Updating: {', '.join(packages_to_update)}\nUpdate "
|
||||
|
||||
if self.ui.restart_checkBox.isChecked():
|
||||
message = message + "and restart app?"
|
||||
else:
|
||||
message = message + "app?"
|
||||
|
||||
msg.setText(message)
|
||||
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
||||
result = msg.exec()
|
||||
|
||||
if result == QMessageBox.Yes:
|
||||
update_results = [] # Store results
|
||||
|
||||
for package in packages_to_update:
|
||||
if package == "OptimaLab35":
|
||||
pkg_info = self.ppu_ol35.update_package()
|
||||
elif package == "optima35":
|
||||
pkg_info = self.ppu_o35.update_package()
|
||||
|
||||
update_results.append(f"{package}: {'Success' if pkg_info[0] else 'Failed'}\n{pkg_info[1]}")
|
||||
|
||||
# Show summary of updates
|
||||
# Show update completion message
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Update Complete")
|
||||
msg.setText("\n\n".join(update_results))
|
||||
msg.setStandardButtons(QMessageBox.Ok)
|
||||
msg.exec()
|
||||
|
||||
# Restart the application after user clicks "OK"
|
||||
if self.ui.restart_checkBox.isChecked():
|
||||
self.restart_program()
|
||||
|
||||
def restart_program(self):
|
||||
"""Restart the Python program after an update."""
|
||||
print("Restarting the application...")
|
||||
# Close all running Qt windows before restarting
|
||||
app = QApplication.instance()
|
||||
if app:
|
||||
app.quit()
|
||||
|
||||
python = sys.executable
|
||||
os.execl(python, python, *sys.argv)
|
||||
|
||||
class PreviewWindow(QMainWindow, Ui_Preview_Window):
|
||||
values_selected = Signal(int, int, bool)
|
||||
# Large ChatGPT with rewrite and bug fixes from me.
|
||||
|
||||
def __init__(self):
|
||||
super(PreviewWindow, self).__init__()
|
||||
self.ui = Ui_Preview_Window()
|
||||
self.ui.setupUi(self)
|
||||
self.o = OptimaManager()
|
||||
self.threadpool = QThreadPool() # Thread pool for managing worker threads
|
||||
|
||||
self.ui.QLabel.setAlignment(Qt.AlignCenter)
|
||||
|
||||
# UI interactions
|
||||
self.ui.load_Button.clicked.connect(self.browse_file)
|
||||
self.ui.update_Button.clicked.connect(self.update_preview)
|
||||
self.ui.close_Button.clicked.connect(self.close_window)
|
||||
|
||||
self.ui.reset_brightness_Button.clicked.connect(lambda: self.ui.brightness_spinBox.setValue(0))
|
||||
self.ui.reset_contrast_Button.clicked.connect(lambda: self.ui.contrast_spinBox.setValue(0))
|
||||
|
||||
# Connect UI elements to `on_ui_change`
|
||||
self.ui.brightness_spinBox.valueChanged.connect(self.on_ui_change)
|
||||
self.ui.brightness_Slider.valueChanged.connect(self.on_ui_change)
|
||||
self.ui.contrast_spinBox.valueChanged.connect(self.on_ui_change)
|
||||
self.ui.contrast_Slider.valueChanged.connect(self.on_ui_change)
|
||||
self.ui.grayscale_checkBox.stateChanged.connect(self.on_ui_change)
|
||||
self.ui_elements(False)
|
||||
self.ui.show_OG_Button.pressed.connect(self.show_OG_image)
|
||||
self.ui.show_OG_Button.released.connect(self.update_preview)
|
||||
|
||||
def on_ui_change(self):
|
||||
"""Triggers update only if live update is enabled."""
|
||||
if self.ui.live_update.isChecked():
|
||||
self.update_preview()
|
||||
|
||||
def browse_file(self):
|
||||
file = QFileDialog.getOpenFileName(self, caption="Select File", filter="Images (*.png *.webp *.jpg *.jpeg)")
|
||||
if file[0]:
|
||||
self.ui.image_path_lineEdit.setText(file[0])
|
||||
self.update_preview()
|
||||
self.ui_elements(True)
|
||||
|
||||
def show_OG_image(self):
|
||||
"""Handles loading and displaying the image in a separate thread."""
|
||||
path = self.ui.image_path_lineEdit.text()
|
||||
|
||||
worker = ImageProcessorWorker(
|
||||
path = path,
|
||||
optima_manager = self.o,
|
||||
brightness = 0,
|
||||
contrast = 0,
|
||||
grayscale = False,
|
||||
resize = self.ui.scale_Slider.value(),
|
||||
callback = self.display_image # Callback to update UI
|
||||
)
|
||||
self.threadpool.start(worker)
|
||||
|
||||
def ui_elements(self, state):
|
||||
self.ui.groupBox_2.setEnabled(state)
|
||||
self.ui.groupBox.setEnabled(state)
|
||||
self.ui.groupBox_5.setEnabled(state)
|
||||
self.ui.show_OG_Button.setEnabled(state)
|
||||
|
||||
def update_preview(self):
|
||||
"""Handles loading and displaying the image in a separate thread."""
|
||||
path = self.ui.image_path_lineEdit.text()
|
||||
|
||||
worker = ImageProcessorWorker(
|
||||
path = path,
|
||||
optima_manager = self.o,
|
||||
brightness = int(self.ui.brightness_spinBox.text()),
|
||||
contrast = int(self.ui.contrast_spinBox.text()),
|
||||
grayscale = self.ui.grayscale_checkBox.isChecked(),
|
||||
resize = self.ui.scale_Slider.value(),
|
||||
callback = self.display_image # Callback to update UI
|
||||
)
|
||||
self.threadpool.start(worker) # Run worker in a thread
|
||||
|
||||
def display_image(self, pixmap):
|
||||
"""Adjusts the image to fit within the QLabel."""
|
||||
if pixmap is None:
|
||||
QMessageBox.warning(self, "Warning", "Error processing image...")
|
||||
return
|
||||
|
||||
max_size = self.ui.QLabel.size()
|
||||
scaled_pixmap = pixmap.scaled(max_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
self.ui.QLabel.setPixmap(scaled_pixmap)
|
||||
self.ui.QLabel.resize(scaled_pixmap.size())
|
||||
|
||||
def resizeEvent(self, event):
|
||||
"""Triggered when the preview window is resized."""
|
||||
file_path = self.ui.image_path_lineEdit.text()
|
||||
if os.path.exists(file_path):
|
||||
self.update_preview() # Re-process and display the image
|
||||
super().resizeEvent(event) # Keep the default behavior
|
||||
|
||||
def close_window(self):
|
||||
"""Emits signal and closes the window."""
|
||||
if self.ui.checkBox.isChecked():
|
||||
self.values_selected.emit(self.ui.brightness_spinBox.value(), self.ui.contrast_spinBox.value(), self.ui.grayscale_checkBox.isChecked())
|
||||
self.close()
|
||||
|
||||
class WorkerSignals(QObject):
|
||||
# ChatGPT
|
||||
progress = Signal(int)
|
||||
|
@ -984,61 +544,3 @@ class ImageProcessorRunnable(QRunnable):
|
|||
self.signals.progress.emit(int((i / len(self.image_files)) * 100))
|
||||
|
||||
self.signals.finished.emit()
|
||||
|
||||
class ImageProcessorWorker(QRunnable):
|
||||
"""Worker class to load and process the image in a separate thread."""
|
||||
# ChatGPT
|
||||
def __init__(self, path, optima_manager, brightness, contrast, grayscale, resize, callback):
|
||||
super().__init__()
|
||||
self.path = path
|
||||
self.optima_manager = optima_manager
|
||||
self.brightness = brightness
|
||||
self.contrast = contrast
|
||||
self.grayscale = grayscale
|
||||
self.resize = resize
|
||||
self.callback = callback # Function to call when processing is done
|
||||
|
||||
@Slot()
|
||||
def run(self):
|
||||
"""Runs the image processing in a separate thread."""
|
||||
if not os.path.isfile(self.path):
|
||||
self.callback(None)
|
||||
return
|
||||
|
||||
try:
|
||||
img = self.optima_manager.process_image_object(
|
||||
image_input_file = self.path,
|
||||
watermark = "PREVIEW",
|
||||
resize = self.resize,
|
||||
grayscale = self.grayscale,
|
||||
brightness = self.brightness,
|
||||
contrast = self.contrast
|
||||
)
|
||||
pixmap = QPixmap.fromImage(img)
|
||||
self.callback(pixmap)
|
||||
except Exception as e:
|
||||
print(f"Error processing image: {e}")
|
||||
self.callback(None)
|
||||
|
||||
def main():
|
||||
u = Utilities(os.path.expanduser(CONFIG_BASE_PATH))
|
||||
app_settings = u.load_settings()
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
|
||||
try:
|
||||
import qdarktheme
|
||||
app_settings["theme"]["theme_pkg"] = True
|
||||
except Exception:
|
||||
app_settings["theme"]["theme_pkg"] = False
|
||||
|
||||
if app_settings["theme"]["use_custom_theme"] and app_settings["theme"]["theme_pkg"]:
|
||||
qdarktheme.setup_theme(app_settings["theme"]["mode"].lower())
|
||||
|
||||
u.save_settings(app_settings)
|
||||
del u
|
||||
window = OptimaLab35()
|
||||
window.show()
|
||||
app.exec()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
167
src/OptimaLab35/previewWindow.py
Normal file
167
src/OptimaLab35/previewWindow.py
Normal file
|
@ -0,0 +1,167 @@
|
|||
import os
|
||||
from optima35.core import OptimaManager
|
||||
|
||||
from OptimaLab35 import __version__
|
||||
|
||||
from .ui import resources_rc
|
||||
from .ui.preview_window import Ui_Preview_Window
|
||||
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
|
||||
from PySide6.QtCore import (
|
||||
QRunnable,
|
||||
QThreadPool,
|
||||
Signal,
|
||||
QObject,
|
||||
QRegularExpression,
|
||||
Qt,
|
||||
QTimer,
|
||||
Slot
|
||||
)
|
||||
|
||||
from PySide6.QtWidgets import (
|
||||
QMessageBox,
|
||||
QApplication,
|
||||
QMainWindow,
|
||||
QFileDialog
|
||||
)
|
||||
|
||||
from PySide6.QtGui import QPixmap, QRegularExpressionValidator, QIcon
|
||||
|
||||
class PreviewWindow(QMainWindow, Ui_Preview_Window):
|
||||
values_selected = Signal(int, int, bool)
|
||||
# Large ChatGPT with rewrite and bug fixes from me.
|
||||
|
||||
def __init__(self):
|
||||
super(PreviewWindow, self).__init__()
|
||||
self.ui = Ui_Preview_Window()
|
||||
self.ui.setupUi(self)
|
||||
self.o = OptimaManager()
|
||||
self.threadpool = QThreadPool() # Thread pool for managing worker threads
|
||||
self.setWindowIcon(QIcon(":app-icon.png"))
|
||||
self.ui.QLabel.setAlignment(Qt.AlignCenter)
|
||||
|
||||
# UI interactions
|
||||
self.ui.load_Button.clicked.connect(self.browse_file)
|
||||
self.ui.update_Button.clicked.connect(self.update_preview)
|
||||
self.ui.close_Button.clicked.connect(self.close_window)
|
||||
|
||||
self.ui.reset_brightness_Button.clicked.connect(lambda: self.ui.brightness_spinBox.setValue(0))
|
||||
self.ui.reset_contrast_Button.clicked.connect(lambda: self.ui.contrast_spinBox.setValue(0))
|
||||
|
||||
# Connect UI elements to `on_ui_change`
|
||||
self.ui.brightness_spinBox.valueChanged.connect(self.on_ui_change)
|
||||
self.ui.brightness_Slider.valueChanged.connect(self.on_ui_change)
|
||||
self.ui.contrast_spinBox.valueChanged.connect(self.on_ui_change)
|
||||
self.ui.contrast_Slider.valueChanged.connect(self.on_ui_change)
|
||||
self.ui.grayscale_checkBox.stateChanged.connect(self.on_ui_change)
|
||||
self.ui_elements(False)
|
||||
self.ui.show_OG_Button.pressed.connect(self.show_OG_image)
|
||||
self.ui.show_OG_Button.released.connect(self.update_preview)
|
||||
|
||||
def on_ui_change(self):
|
||||
"""Triggers update only if live update is enabled."""
|
||||
if self.ui.live_update.isChecked():
|
||||
self.update_preview()
|
||||
|
||||
def browse_file(self):
|
||||
file = QFileDialog.getOpenFileName(self, caption="Select File", filter="Images (*.png *.webp *.jpg *.jpeg)")
|
||||
if file[0]:
|
||||
self.ui.image_path_lineEdit.setText(file[0])
|
||||
self.update_preview()
|
||||
self.ui_elements(True)
|
||||
|
||||
def show_OG_image(self):
|
||||
"""Handles loading and displaying the image in a separate thread."""
|
||||
path = self.ui.image_path_lineEdit.text()
|
||||
|
||||
worker = ImageProcessorWorker(
|
||||
path = path,
|
||||
optima_manager = self.o,
|
||||
brightness = 0,
|
||||
contrast = 0,
|
||||
grayscale = False,
|
||||
resize = self.ui.scale_Slider.value(),
|
||||
callback = self.display_image # Callback to update UI
|
||||
)
|
||||
self.threadpool.start(worker)
|
||||
|
||||
def ui_elements(self, state):
|
||||
self.ui.groupBox_2.setEnabled(state)
|
||||
self.ui.groupBox.setEnabled(state)
|
||||
self.ui.groupBox_5.setEnabled(state)
|
||||
self.ui.show_OG_Button.setEnabled(state)
|
||||
|
||||
def update_preview(self):
|
||||
"""Handles loading and displaying the image in a separate thread."""
|
||||
path = self.ui.image_path_lineEdit.text()
|
||||
|
||||
worker = ImageProcessorWorker(
|
||||
path = path,
|
||||
optima_manager = self.o,
|
||||
brightness = int(self.ui.brightness_spinBox.text()),
|
||||
contrast = int(self.ui.contrast_spinBox.text()),
|
||||
grayscale = self.ui.grayscale_checkBox.isChecked(),
|
||||
resize = self.ui.scale_Slider.value(),
|
||||
callback = self.display_image # Callback to update UI
|
||||
)
|
||||
self.threadpool.start(worker) # Run worker in a thread
|
||||
|
||||
def display_image(self, pixmap):
|
||||
"""Adjusts the image to fit within the QLabel."""
|
||||
if pixmap is None:
|
||||
QMessageBox.warning(self, "Warning", "Error processing image...")
|
||||
return
|
||||
|
||||
max_size = self.ui.QLabel.size()
|
||||
scaled_pixmap = pixmap.scaled(max_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
self.ui.QLabel.setPixmap(scaled_pixmap)
|
||||
self.ui.QLabel.resize(scaled_pixmap.size())
|
||||
|
||||
def resizeEvent(self, event):
|
||||
"""Triggered when the preview window is resized."""
|
||||
file_path = self.ui.image_path_lineEdit.text()
|
||||
if os.path.exists(file_path):
|
||||
self.update_preview() # Re-process and display the image
|
||||
super().resizeEvent(event) # Keep the default behavior
|
||||
|
||||
def close_window(self):
|
||||
"""Emits signal and closes the window."""
|
||||
if self.ui.checkBox.isChecked():
|
||||
self.values_selected.emit(self.ui.brightness_spinBox.value(), self.ui.contrast_spinBox.value(), self.ui.grayscale_checkBox.isChecked())
|
||||
self.close()
|
||||
|
||||
class ImageProcessorWorker(QRunnable):
|
||||
"""Worker class to load and process the image in a separate thread."""
|
||||
# ChatGPT
|
||||
def __init__(self, path, optima_manager, brightness, contrast, grayscale, resize, callback):
|
||||
super().__init__()
|
||||
self.path = path
|
||||
self.optima_manager = optima_manager
|
||||
self.brightness = brightness
|
||||
self.contrast = contrast
|
||||
self.grayscale = grayscale
|
||||
self.resize = resize
|
||||
self.callback = callback # Function to call when processing is done
|
||||
|
||||
@Slot()
|
||||
def run(self):
|
||||
"""Runs the image processing in a separate thread."""
|
||||
if not os.path.isfile(self.path):
|
||||
self.callback(None)
|
||||
return
|
||||
|
||||
try:
|
||||
img = self.optima_manager.process_image_object(
|
||||
image_input_file = self.path,
|
||||
watermark = "PREVIEW",
|
||||
resize = self.resize,
|
||||
grayscale = self.grayscale,
|
||||
brightness = self.brightness,
|
||||
contrast = self.contrast
|
||||
)
|
||||
pixmap = QPixmap.fromImage(img)
|
||||
self.callback(pixmap)
|
||||
except Exception as e:
|
||||
print(f"Error processing image: {e}")
|
||||
self.callback(None)
|
357
src/OptimaLab35/settingsWindow.py
Normal file
357
src/OptimaLab35/settingsWindow.py
Normal file
|
@ -0,0 +1,357 @@
|
|||
import sys
|
||||
import os
|
||||
from datetime import datetime
|
||||
from PyPiUpdater import PyPiUpdater
|
||||
|
||||
from OptimaLab35 import __version__
|
||||
from .const import (
|
||||
CONFIG_BASE_PATH
|
||||
)
|
||||
|
||||
from .ui import resources_rc
|
||||
from .utils.utility import Utilities
|
||||
from .ui.settings_window import Ui_Settings_Window
|
||||
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
|
||||
from PySide6.QtCore import (
|
||||
QRegularExpression,
|
||||
Qt,
|
||||
QTimer
|
||||
)
|
||||
|
||||
from PySide6.QtWidgets import (
|
||||
QMessageBox,
|
||||
QApplication,
|
||||
QMainWindow
|
||||
)
|
||||
|
||||
from PySide6.QtGui import QIcon
|
||||
|
||||
class SettingsWindow(QMainWindow, Ui_Settings_Window):
|
||||
# Mixture of code by me, code/functions refactored by ChatGPT and code directly from ChatGPT
|
||||
def __init__(self, optimalab35_localversion, optima35_localversion):
|
||||
super(SettingsWindow, self).__init__()
|
||||
self.ui = Ui_Settings_Window()
|
||||
self.ui.setupUi(self)
|
||||
self.u = Utilities(os.path.expanduser(CONFIG_BASE_PATH))
|
||||
self.app_settings = self.u.load_settings()
|
||||
self.dev_mode = True if optimalab35_localversion == "0.0.1" else False
|
||||
self.setWindowIcon(QIcon(":app-icon.png"))
|
||||
|
||||
# Update log file location
|
||||
self.update_log_file = os.path.expanduser(f"{CONFIG_BASE_PATH}/update_log.json")
|
||||
# Store local versions
|
||||
self.optimalab35_localversion = optimalab35_localversion
|
||||
self.optima35_localversion = optima35_localversion
|
||||
# Create PyPiUpdater instances
|
||||
self.ppu_ol35 = PyPiUpdater("OptimaLab35", self.optimalab35_localversion, self.update_log_file)
|
||||
self.ppu_o35 = PyPiUpdater("optima35", self.optima35_localversion, self.update_log_file)
|
||||
self.ol35_last_state = self.ppu_ol35.get_last_state()
|
||||
self.o35_last_state = self.ppu_o35.get_last_state()
|
||||
# Track which packages need an update
|
||||
self.updates_available = {"OptimaLab35": False, "optima35": False}
|
||||
self.define_gui_interaction()
|
||||
|
||||
def define_gui_interaction(self):
|
||||
"""Setup UI interactions."""
|
||||
# Updater related
|
||||
self.ui.label_optimalab35_localversion.setText(self.optimalab35_localversion)
|
||||
self.ui.label_optima35_localversion.setText(self.optima35_localversion)
|
||||
|
||||
self.ui.label_latest_version.setText("Latest version")
|
||||
self.ui.label_optimalab35_latestversion.setText("...")
|
||||
self.ui.label_optima35_latestversion.setText("...")
|
||||
|
||||
self.ui.update_and_restart_Button.setEnabled(False)
|
||||
|
||||
# Connect buttons to functions
|
||||
self.ui.check_for_update_Button.clicked.connect(self.check_for_updates)
|
||||
self.ui.update_and_restart_Button.clicked.connect(self.update_and_restart)
|
||||
self.ui.label_last_check.setText(f"Last check: {self.time_to_string(self.ol35_last_state[0])}")
|
||||
self.ui.dev_widget.setVisible(False)
|
||||
|
||||
# Timer for long press detection
|
||||
self.timer = QTimer()
|
||||
self.timer.setSingleShot(True)
|
||||
self.timer.timeout.connect(self.toggle_dev_ui)
|
||||
|
||||
# Connect button press/release
|
||||
self.ui.check_for_update_Button.pressed.connect(self.start_long_press)
|
||||
self.ui.check_for_update_Button.released.connect(self.cancel_long_press)
|
||||
self.ui.label_5.setText('<li><a href="https://gitlab.com/CodeByMrFinchum/OptimaLab35/-/blob/main/CHANGELOG.md?ref_type=heads">Changelog</a></li>')
|
||||
self.ui.label_5.setOpenExternalLinks(True)
|
||||
#settings related
|
||||
self.load_settings_into_ui()
|
||||
self.ui.reset_exif_Button.clicked.connect(self.ask_reset_exif)
|
||||
self.ui.save_and_close_Button.clicked.connect(self.save_and_close)
|
||||
self.ui.save_and_restart_Button.clicked.connect(self.save_and_restart)
|
||||
|
||||
if os.name == "nt": # Disable restart app when windows.
|
||||
self.ui.save_and_restart_Button.setVisible(False)
|
||||
self.ui.restart_checkBox.setChecked(False)
|
||||
self.ui.restart_checkBox.setVisible(False)
|
||||
|
||||
# setting related
|
||||
def load_settings_into_ui(self):
|
||||
"""Loads the settings into the UI elements."""
|
||||
settings = self.app_settings
|
||||
theme_mode = settings["theme"]["mode"]
|
||||
use_custom_theme = settings["theme"]["use_custom_theme"]
|
||||
pkg_available = settings["theme"]["theme_pkg"]
|
||||
|
||||
if pkg_available:
|
||||
index = self.ui.theme_selection_comboBox.findText(theme_mode, QtCore.Qt.MatchFlag.MatchExactly)
|
||||
if index != -1:
|
||||
self.ui.theme_selection_comboBox.setCurrentIndex(index)
|
||||
self.ui.enable_theme_checkBox.setChecked(use_custom_theme)
|
||||
self.ui.install_pkg_Button.setVisible(False)
|
||||
self.ui.enable_theme_checkBox.setEnabled(True)
|
||||
else:
|
||||
self.ui.enable_theme_checkBox.setEnabled(False)
|
||||
self.ui.install_pkg_Button.clicked.connect(self.install_theme_pkg)
|
||||
|
||||
def install_theme_pkg(self):
|
||||
a = self.ppu_ol35.install_package("PyQtDarkTheme-fork")
|
||||
self.ui.install_pkg_Button.setEnabled(False)
|
||||
self.ui.install_pkg_Button.setText("Please wait...")
|
||||
|
||||
msg_box = QMessageBox()
|
||||
msg_box.setIcon(QMessageBox.Information)
|
||||
msg_box.setWindowTitle("Message")
|
||||
msg_box.setText(a[1])
|
||||
msg_box.setStandardButtons(QMessageBox.Ok)
|
||||
msg_box.exec()
|
||||
if a[0]:
|
||||
self.app_settings["theme"]["theme_pkg"] = True
|
||||
self.load_settings_into_ui()
|
||||
else:
|
||||
self.ui.install_pkg_Button.setEnabled(True)
|
||||
self.ui.install_pkg_Button.setText("Try again?")
|
||||
|
||||
def save_settings(self):
|
||||
self.app_settings["theme"]["mode"] = self.ui.theme_selection_comboBox.currentText()
|
||||
self.app_settings["theme"]["use_custom_theme"] = self.ui.enable_theme_checkBox.isChecked()
|
||||
self.u.save_settings(self.app_settings)
|
||||
|
||||
def save_and_close(self):
|
||||
self.save_settings()
|
||||
self.close()
|
||||
|
||||
def save_and_restart(self):
|
||||
msg = QMessageBox()
|
||||
msg.setIcon(QMessageBox.Icon.Question)
|
||||
msg.setWindowTitle("Confirm Reset")
|
||||
msg.setText("Are you sure you want to restart the app?")
|
||||
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
||||
|
||||
# Show the message box and wait for the user's response
|
||||
response = msg.exec()
|
||||
|
||||
# Check response and perform action
|
||||
if response == QMessageBox.StandardButton.Yes:
|
||||
self.save_settings()
|
||||
self.restart_program()
|
||||
else:
|
||||
pass # Do nothing if "No" is selected
|
||||
|
||||
def ask_reset_exif(self):
|
||||
"""Shows a dialog to ask the user if they are sure about resetting EXIF options to default."""
|
||||
# Create a QMessageBox with a Yes/No question
|
||||
msg = QMessageBox()
|
||||
msg.setIcon(QMessageBox.Icon.Question)
|
||||
msg.setWindowTitle("Confirm Reset")
|
||||
msg.setText("Are you sure you want to reset the EXIF options to default?")
|
||||
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
||||
|
||||
# Show the message box and wait for the user's response
|
||||
response = msg.exec()
|
||||
|
||||
# Check response and perform action
|
||||
if response == QMessageBox.StandardButton.Yes:
|
||||
self.u.default_exif() # Reset EXIF options to default
|
||||
else:
|
||||
pass # Do nothing if "No" is selected
|
||||
|
||||
# update related parts
|
||||
def start_long_press(self):
|
||||
"""Start the timer when button is pressed."""
|
||||
# brave AI
|
||||
self.timer.start(1000) # 1-second long press
|
||||
|
||||
def cancel_long_press(self):
|
||||
"""Cancel long press if released early."""
|
||||
# brave AI
|
||||
self.timer.stop()
|
||||
|
||||
def toggle_dev_ui(self):
|
||||
"""Show or hide the hidden UI when long press is detected."""
|
||||
self.ui.dev_widget.setVisible(True)
|
||||
|
||||
self.ui.check_local_Button.clicked.connect(self.local_check_for_updates)
|
||||
self.ui.update_local_Button.clicked.connect(self.local_update)
|
||||
|
||||
def local_check_for_updates(self):
|
||||
dist_folder = os.path.expanduser("~/.config/OptimaLab35/dist/")
|
||||
self.ui.label_optimalab35_latestversion.setText("Checking...")
|
||||
self.ui.label_optima35_latestversion.setText("Checking...")
|
||||
|
||||
# Check OptimaLab35 update
|
||||
ol35_pkg_info = self.ppu_ol35.check_update_local(dist_folder)
|
||||
if ol35_pkg_info[0] is None:
|
||||
self.ui.label_optimalab35_latestversion.setText(ol35_pkg_info[1][0:13])
|
||||
else:
|
||||
self.ui.label_optimalab35_latestversion.setText(ol35_pkg_info[1])
|
||||
self.updates_available["OptimaLab35"] = ol35_pkg_info[0]
|
||||
|
||||
# Check optima35 update
|
||||
o35_pkg_info = self.ppu_o35.check_update_local(dist_folder)
|
||||
if o35_pkg_info[0] is None:
|
||||
self.ui.label_optima35_latestversion.setText(o35_pkg_info[1][0:13])
|
||||
else:
|
||||
self.ui.label_optima35_latestversion.setText(o35_pkg_info[1])
|
||||
self.updates_available["optima35"] = o35_pkg_info[0]
|
||||
|
||||
def local_update(self):
|
||||
dist_folder = os.path.expanduser("~/.config/OptimaLab35/dist/")
|
||||
packages_to_update = [pkg for pkg, update in self.updates_available.items() if update]
|
||||
|
||||
if not packages_to_update:
|
||||
QMessageBox.information(self, "Update", "No updates available.")
|
||||
return
|
||||
|
||||
# Confirm update
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Update Available")
|
||||
message = f"Updating: {', '.join(packages_to_update)}\nUpdate "
|
||||
|
||||
if self.ui.restart_checkBox.isChecked():
|
||||
message = message + "and restart app?"
|
||||
else:
|
||||
message = message + "app?"
|
||||
|
||||
msg.setText(message)
|
||||
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
||||
result = msg.exec()
|
||||
|
||||
if result == QMessageBox.Yes:
|
||||
update_results = [] # Store results
|
||||
|
||||
for package in packages_to_update:
|
||||
if package == "OptimaLab35":
|
||||
pkg_info = self.ppu_ol35.update_from_local(dist_folder)
|
||||
elif package == "optima35":
|
||||
pkg_info = self.ppu_o35.update_from_local(dist_folder)
|
||||
|
||||
update_results.append(f"{package}: {'Success' if pkg_info[0] else 'Failed'}\n{pkg_info[1]}")
|
||||
|
||||
# Show summary of updates
|
||||
# Show update completion message
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Update Complete")
|
||||
msg.setText("\n\n".join(update_results))
|
||||
msg.setStandardButtons(QMessageBox.Ok)
|
||||
msg.exec()
|
||||
|
||||
# Restart the application after user clicks "OK"
|
||||
if self.ui.restart_checkBox.isChecked():
|
||||
self.restart_program()
|
||||
|
||||
def time_to_string(self, time_time):
|
||||
try:
|
||||
dt_obj = datetime.fromtimestamp(time_time)
|
||||
date_string = dt_obj.strftime("%d %h %H:%M")
|
||||
return date_string
|
||||
except TypeError:
|
||||
return "Missing information"
|
||||
|
||||
def check_for_updates(self):
|
||||
"""Check for updates and update the UI."""
|
||||
self.ui.check_for_update_Button.setEnabled(False)
|
||||
self.ui.label_optimalab35_latestversion.setText("Checking...")
|
||||
self.ui.label_optima35_latestversion.setText("Checking...")
|
||||
|
||||
# Check OptimaLab35 update
|
||||
ol35_pkg_info = self.ppu_ol35.check_for_update()
|
||||
if ol35_pkg_info[0] is None:
|
||||
self.ui.label_optimalab35_latestversion.setText(ol35_pkg_info[1][0:13])
|
||||
else:
|
||||
self.ui.label_optimalab35_latestversion.setText(ol35_pkg_info[1])
|
||||
self.updates_available["OptimaLab35"] = ol35_pkg_info[0]
|
||||
|
||||
# Check optima35 update
|
||||
o35_pkg_info = self.ppu_o35.check_for_update()
|
||||
if o35_pkg_info[0] is None:
|
||||
self.ui.label_optima35_latestversion.setText(o35_pkg_info[1][0:13])
|
||||
else:
|
||||
self.ui.label_optima35_latestversion.setText(o35_pkg_info[1])
|
||||
self.updates_available["optima35"] = o35_pkg_info[0]
|
||||
|
||||
# Enable update button if any update is available
|
||||
if any(self.updates_available.values()):
|
||||
if self.dev_mode:
|
||||
self.ui.update_and_restart_Button.setEnabled(False)
|
||||
self.ui.update_and_restart_Button.setText("Update disabled")
|
||||
else:
|
||||
self.ui.update_and_restart_Button.setEnabled(True)
|
||||
|
||||
last_date = self.time_to_string(self.ppu_ol35.get_last_state()[0])
|
||||
self.ui.label_last_check.setText(f"Last check: {last_date}")
|
||||
self.ui.label_latest_version.setText("Online version")
|
||||
self.ui.check_for_update_Button.setEnabled(True)
|
||||
|
||||
def update_and_restart(self):
|
||||
"""Update selected packages and restart the application."""
|
||||
packages_to_update = [pkg for pkg, update in self.updates_available.items() if update]
|
||||
|
||||
if not packages_to_update:
|
||||
QMessageBox.information(self, "Update", "No updates available.")
|
||||
return
|
||||
|
||||
# Confirm update
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Update Available")
|
||||
message = f"Updating: {', '.join(packages_to_update)}\nUpdate "
|
||||
|
||||
if self.ui.restart_checkBox.isChecked():
|
||||
message = message + "and restart app?"
|
||||
else:
|
||||
message = message + "app?"
|
||||
|
||||
msg.setText(message)
|
||||
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
||||
result = msg.exec()
|
||||
|
||||
if result == QMessageBox.Yes:
|
||||
update_results = [] # Store results
|
||||
|
||||
for package in packages_to_update:
|
||||
if package == "OptimaLab35":
|
||||
pkg_info = self.ppu_ol35.update_package()
|
||||
elif package == "optima35":
|
||||
pkg_info = self.ppu_o35.update_package()
|
||||
|
||||
update_results.append(f"{package}: {'Success' if pkg_info[0] else 'Failed'}\n{pkg_info[1]}")
|
||||
|
||||
# Show summary of updates
|
||||
# Show update completion message
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Update Complete")
|
||||
msg.setText("\n\n".join(update_results))
|
||||
msg.setStandardButtons(QMessageBox.Ok)
|
||||
msg.exec()
|
||||
|
||||
# Restart the application after user clicks "OK"
|
||||
if self.ui.restart_checkBox.isChecked():
|
||||
self.restart_program()
|
||||
|
||||
def restart_program(self):
|
||||
"""Restart the Python program after an update."""
|
||||
print("Restarting the application...")
|
||||
# Close all running Qt windows before restarting
|
||||
app = QApplication.instance()
|
||||
if app:
|
||||
app.quit()
|
||||
|
||||
python = sys.executable
|
||||
os.execl(python, python, *sys.argv)
|
Loading…
Add table
Add a link
Reference in a new issue