refactored code from gui.py to several files.
This commit is contained in:
parent
c0f0e873d8
commit
bfea75f843
4 changed files with 562 additions and 510 deletions
|
@ -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__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from .ui import resources_rc
|
|
||||||
from PyPiUpdater import PyPiUpdater
|
|
||||||
from optima35.core import OptimaManager
|
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 OptimaLab35 import __version__
|
||||||
from .const import (
|
from .const import (
|
||||||
APPLICATION_NAME,
|
APPLICATION_NAME,
|
||||||
CONFIG_BASE_PATH
|
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 import QtWidgets, QtCore
|
||||||
|
|
||||||
from PySide6.QtCore import (
|
from PySide6.QtCore import (
|
||||||
|
@ -26,9 +25,7 @@ from PySide6.QtCore import (
|
||||||
Signal,
|
Signal,
|
||||||
QObject,
|
QObject,
|
||||||
QRegularExpression,
|
QRegularExpression,
|
||||||
Qt,
|
Qt
|
||||||
QTimer,
|
|
||||||
Slot
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
|
@ -38,7 +35,7 @@ from PySide6.QtWidgets import (
|
||||||
QFileDialog
|
QFileDialog
|
||||||
)
|
)
|
||||||
|
|
||||||
from PySide6.QtGui import QPixmap, QRegularExpressionValidator, QIcon
|
from PySide6.QtGui import QRegularExpressionValidator, QIcon
|
||||||
|
|
||||||
class OptimaLab35(QMainWindow, Ui_MainWindow):
|
class OptimaLab35(QMainWindow, Ui_MainWindow):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -99,8 +96,6 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
|
||||||
validator = QRegularExpressionValidator(regex)
|
validator = QRegularExpressionValidator(regex)
|
||||||
self.ui.lat_lineEdit.setValidator(validator)
|
self.ui.lat_lineEdit.setValidator(validator)
|
||||||
self.ui.long_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.
|
# UI related function, changing parts, open, etc.
|
||||||
def open_preview_window(self):
|
def open_preview_window(self):
|
||||||
|
@ -501,441 +496,6 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
|
||||||
QApplication.closeAllWindows()
|
QApplication.closeAllWindows()
|
||||||
event.accept()
|
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):
|
class WorkerSignals(QObject):
|
||||||
# ChatGPT
|
# ChatGPT
|
||||||
progress = Signal(int)
|
progress = Signal(int)
|
||||||
|
@ -984,61 +544,3 @@ class ImageProcessorRunnable(QRunnable):
|
||||||
self.signals.progress.emit(int((i / len(self.image_files)) * 100))
|
self.signals.progress.emit(int((i / len(self.image_files)) * 100))
|
||||||
|
|
||||||
self.signals.finished.emit()
|
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