Compare commits

...

2 commits
1.8.2 ... main

Author SHA1 Message Date
08b6937142
Patch: changed year to include 2026
All checks were successful
ci/woodpecker/pr/woodpecker_ci Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker_ci Pipeline was successful
ci/woodpecker/push/woodpecker_ci Pipeline was successful
ci/woodpecker/tag/woodpecker_ci Pipeline was successful
2026-01-04 11:13:54 +01:00
547dec03a7
Fix: fixed wrong link to changelog
All checks were successful
ci/woodpecker/push/woodpecker_ci Pipeline was successful
ci/woodpecker/tag/woodpecker_ci Pipeline was successful
2026-01-04 10:47:58 +01:00
2 changed files with 215 additions and 142 deletions

View file

@ -1,42 +1,31 @@
import os import os
from datetime import datetime from datetime import datetime
from optima35.core import OptimaManager from optima35.core import OptimaManager
from PySide6 import QtCore, QtWidgets
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 ( from PySide6.QtCore import (
QRunnable, QDate,
QThreadPool,
Signal,
QObject, QObject,
QRegularExpression, QRegularExpression,
QRunnable,
Qt, Qt,
QDate QThreadPool,
Signal,
) )
from PySide6.QtGui import QIcon, QRegularExpressionValidator
from PySide6.QtWidgets import QApplication, QFileDialog, QMainWindow, QMessageBox
from PySide6.QtWidgets import ( from OptimaLab35 import __version__
QMessageBox,
QApplication, from .const import APPLICATION_NAME, CONFIG_BASE_PATH
QMainWindow, from .previewWindow import PreviewWindow
QFileDialog from .settingsWindow import SettingsWindow
) from .ui import resources_rc
from .ui.exif_handler_window import ExifEditor
from .ui.main_window import Ui_MainWindow
from .ui.simple_dialog import SimpleDialog # Import the SimpleDialog class
from .utils.utility import Utilities
from PySide6.QtGui import QRegularExpressionValidator, QIcon
class OptimaLab35(QMainWindow, Ui_MainWindow): class OptimaLab35(QMainWindow, Ui_MainWindow):
def __init__(self): def __init__(self):
@ -46,7 +35,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
self.o = OptimaManager() self.o = OptimaManager()
self.u = Utilities(os.path.expanduser(CONFIG_BASE_PATH)) self.u = Utilities(os.path.expanduser(CONFIG_BASE_PATH))
self.app_settings = self.u.load_settings() self.app_settings = self.u.load_settings()
self.thread_pool = QThreadPool() # multi thread ChatGPT self.thread_pool = QThreadPool() # multi thread ChatGPT
# Initiate internal object # Initiate internal object
self.exif_file = os.path.expanduser(f"{CONFIG_BASE_PATH}/exif.yaml") self.exif_file = os.path.expanduser(f"{CONFIG_BASE_PATH}/exif.yaml")
self.available_exif_data = None self.available_exif_data = None
@ -98,6 +87,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
self.ui.lat_lineEdit.setValidator(validator) self.ui.lat_lineEdit.setValidator(validator)
self.ui.long_lineEdit.setValidator(validator) self.ui.long_lineEdit.setValidator(validator)
self.ui.dateEdit.setDate(QDate.currentDate()) self.ui.dateEdit.setDate(QDate.currentDate())
# UI related function, changing parts, open, etc. # UI related function, changing parts, open, etc.
def open_preview_window(self): def open_preview_window(self):
self.preview_window = PreviewWindow() self.preview_window = PreviewWindow()
@ -118,7 +108,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
def info_window(self): def info_window(self):
info_text = f""" info_text = f"""
<h3>{self.name} v{self.version}</h3> <h3>{self.name} v{self.version}</h3>
<p>(C) 2024-2025 Mr Finchum aka CodeByMrFinchum</p> <p>(C) 2024-2026 Mr Finchum aka CodeByMrFinchum</p>
<p>{self.name} is a GUI for {self.o.name} (v{self.o.version}), enhancing its functionality with a user-friendly interface for efficient image and metadata management.</p> <p>{self.name} is a GUI for {self.o.name} (v{self.o.version}), enhancing its functionality with a user-friendly interface for efficient image and metadata management.</p>
<h4>Features:</h4> <h4>Features:</h4>
@ -185,8 +175,12 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
filtered.append(stripped) filtered.append(stripped)
# ignore anything else # ignore anything else
# Sort: NA first, then valid times ascending # Sort: NA first, then valid times ascending
return sorted(filtered, key=lambda x: (0, 0) if (x is None or str(x).strip().upper() in {"NA"}) return sorted(
else (1, self.parse_time(x))) filtered,
key=lambda x: (0, 0)
if (x is None or str(x).strip().upper() in {"NA"})
else (1, self.parse_time(x)),
)
def sort_dict_of_lists(self, input_dict): def sort_dict_of_lists(self, input_dict):
# Partily ChatGPT # Partily ChatGPT
@ -204,7 +198,9 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
elif all(isinstance(x, str) for x in lst): elif all(isinstance(x, str) for x in lst):
sorted_dict[key] = sorted( sorted_dict[key] = sorted(
lst, lst,
key=lambda x: (0, x.lower()) if str(x).lower() == "na" else (1, str(x).lower()) key=lambda x: (0, x.lower())
if str(x).lower() == "na"
else (1, str(x).lower()),
) )
return sorted_dict return sorted_dict
@ -246,29 +242,29 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
self.populate_comboboxes(combo_mapping) self.populate_comboboxes(combo_mapping)
def update_quality_options(self): def update_quality_options(self):
"""Update visibility of quality settings based on selected format.""" """Update visibility of quality settings based on selected format."""
# Partly ChatGPT # Partly ChatGPT
selected_format = self.ui.image_type.currentText() selected_format = self.ui.image_type.currentText()
# Hide all quality settings # Hide all quality settings
self.ui.png_quality_spinBox.setVisible(False) self.ui.png_quality_spinBox.setVisible(False)
self.ui.jpg_quality_spinBox.setVisible(False) self.ui.jpg_quality_spinBox.setVisible(False)
self.ui.jpg_quality_Slider.setVisible(False) self.ui.jpg_quality_Slider.setVisible(False)
self.ui.png_quality_Slider.setVisible(False) self.ui.png_quality_Slider.setVisible(False)
self.ui.quality_label_1.setVisible(False) self.ui.quality_label_1.setVisible(False)
self.ui.quality_label_2.setVisible(False) self.ui.quality_label_2.setVisible(False)
# Show relevant settings # Show relevant settings
if selected_format == "jpg": if selected_format == "jpg":
self.ui.jpg_quality_spinBox.setVisible(True) self.ui.jpg_quality_spinBox.setVisible(True)
self.ui.jpg_quality_Slider.setVisible(True) self.ui.jpg_quality_Slider.setVisible(True)
self.ui.quality_label_1.setVisible(True) self.ui.quality_label_1.setVisible(True)
elif selected_format == "webp": elif selected_format == "webp":
self.ui.jpg_quality_spinBox.setVisible(True) self.ui.jpg_quality_spinBox.setVisible(True)
self.ui.jpg_quality_Slider.setVisible(True) self.ui.jpg_quality_Slider.setVisible(True)
self.ui.quality_label_1.setVisible(True) self.ui.quality_label_1.setVisible(True)
elif selected_format == "png": elif selected_format == "png":
self.ui.png_quality_spinBox.setVisible(True) self.ui.png_quality_spinBox.setVisible(True)
self.ui.png_quality_Slider.setVisible(True) self.ui.png_quality_Slider.setVisible(True)
self.ui.quality_label_2.setVisible(True) self.ui.quality_label_2.setVisible(True)
def browse_input_folder(self): def browse_input_folder(self):
folder = QFileDialog.getExistingDirectory(self, "Select Input Folder") folder = QFileDialog.getExistingDirectory(self, "Select Input Folder")
@ -280,7 +276,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
if folder: if folder:
self.ui.output_path.setText(folder) self.ui.output_path.setText(folder)
def change_statusbar(self, msg, timeout = 500): def change_statusbar(self, msg, timeout=500):
self.ui.statusBar.showMessage(msg, timeout) self.ui.statusBar.showMessage(msg, timeout)
# Core functions # Core functions
@ -291,7 +287,9 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
def image_list_from_folder(self, path): def image_list_from_folder(self, path):
image_files = [ image_files = [
f for f in os.listdir(path) if f.lower().endswith((".png", ".jpg", ".jpeg", ".webp")) f
for f in os.listdir(path)
if f.lower().endswith((".png", ".jpg", ".jpeg", ".webp"))
] ]
image_files.sort() image_files.sort()
return image_files return image_files
@ -307,11 +305,17 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
if process == "image": if process == "image":
if not input_folder or not output_folder: if not input_folder or not output_folder:
QMessageBox.warning(self, "Warning", "Input or output folder not selected") QMessageBox.warning(
self, "Warning", "Input or output folder not selected"
)
return False return False
if not input_folder_valid or not output_folder_valid: if not input_folder_valid or not output_folder_valid:
QMessageBox.warning(self, "Warning", f"Input location {input_folder_valid}\nOutput folder {output_folder_valid}...") QMessageBox.warning(
self,
"Warning",
f"Input location {input_folder_valid}\nOutput folder {output_folder_valid}...",
)
return False return False
if len(self.image_list_from_folder(output_folder)) != 0: if len(self.image_list_from_folder(output_folder)) != 0:
@ -326,7 +330,6 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
return False return False
elif process == "exif": elif process == "exif":
if not input_folder: if not input_folder:
QMessageBox.warning(self, "Warning", "Input not selected") QMessageBox.warning(self, "Warning", "Input not selected")
return False return False
@ -342,15 +345,19 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
if reply == QMessageBox.No: if reply == QMessageBox.No:
return False return False
if not input_folder_valid : if not input_folder_valid:
QMessageBox.warning(self, "Warning", f"Input location {input_folder_valid}") QMessageBox.warning(
self, "Warning", f"Input location {input_folder_valid}"
)
return False return False
else: else:
print("Something went wrong") print("Something went wrong")
if len(image_list) == 0: if len(image_list) == 0:
QMessageBox.warning(self, "Warning", "Selected folder has no supported files.") QMessageBox.warning(
self, "Warning", "Selected folder has no supported files."
)
return False return False
return True return True
@ -369,7 +376,9 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
image_list = self.image_list_from_folder(self.settings["input_folder"]) image_list = self.image_list_from_folder(self.settings["input_folder"])
# Create a worker ChatGPT # Create a worker ChatGPT
worker = ImageProcessorRunnable(image_list, self.settings, self.handle_qprogressbar) worker = ImageProcessorRunnable(
image_list, self.settings, self.handle_qprogressbar
)
worker.signals.finished.connect(self.on_processing_finished) worker.signals.finished.connect(self.on_processing_finished)
# Start worker in thread pool ChatGPT # Start worker in thread pool ChatGPT
self.thread_pool.start(worker) self.thread_pool.start(worker)
@ -387,13 +396,13 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
i = 1 i = 1
for image_file in image_files: for image_file in image_files:
input_path = os.path.join(input_folder, image_file) input_path = os.path.join(input_folder, image_file)
self.o.insert_exif_to_image( self.o.insert_exif_to_image(
exif_dict = self.settings["user_selected_exif"], exif_dict=self.settings["user_selected_exif"],
image_path = input_path, image_path=input_path,
gps = self.settings["gps"]) gps=self.settings["gps"],
)
self.change_statusbar(image_file, 100) self.change_statusbar(image_file, 100)
self.handle_qprogressbar(int((i / len(image_files)) * 100)) self.handle_qprogressbar(int((i / len(image_files)) * 100))
i += 1 i += 1
@ -415,7 +424,11 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
image_list = self.image_list_from_folder(self.settings["input_folder"]) image_list = self.image_list_from_folder(self.settings["input_folder"])
print(image_list) print(image_list)
if not self.control_ending(image_list): if not self.control_ending(image_list):
QMessageBox.warning(self, "Warning", f"Error: one or more filenames do not end on a number.\nCan not adjust time") QMessageBox.warning(
self,
"Warning",
f"Error: one or more filenames do not end on a number.\nCan not adjust time",
)
self.toggle_buttons(True) self.toggle_buttons(True)
return return
@ -424,19 +437,19 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
self.toggle_buttons(True) self.toggle_buttons(True)
QMessageBox.information(self, "Information", "Finished") QMessageBox.information(self, "Information", "Finished")
def get_checkbox_value(self, checkbox, default = None): def get_checkbox_value(self, checkbox, default=None):
"""Helper function to get the value of a checkbox or a default value.""" """Helper function to get the value of a checkbox or a default value."""
return checkbox.isChecked() if checkbox else default return checkbox.isChecked() if checkbox else default
def get_spinbox_value(self, spinbox, default = None): def get_spinbox_value(self, spinbox, default=None):
"""Helper function to get the value of a spinbox and handle empty input.""" """Helper function to get the value of a spinbox and handle empty input."""
return int(spinbox.text()) if spinbox.text() else default return int(spinbox.text()) if spinbox.text() else default
def get_combobox_value(self, combobox, default = None): def get_combobox_value(self, combobox, default=None):
"""Helper function to get the value of a combobox.""" """Helper function to get the value of a combobox."""
return combobox.currentIndex() + 1 if combobox.currentIndex() != -1 else default return combobox.currentIndex() + 1 if combobox.currentIndex() != -1 else default
def get_text_value(self, lineedit, default = None): def get_text_value(self, lineedit, default=None):
"""Helper function to get the value of a text input field.""" """Helper function to get the value of a text input field."""
return lineedit.text() if lineedit.text() else default return lineedit.text() if lineedit.text() else default
@ -464,12 +477,21 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
user_data["lens"] = self.ui.lens_comboBox.currentText() user_data["lens"] = self.ui.lens_comboBox.currentText()
user_data["iso"] = self.ui.iso_comboBox.currentText() user_data["iso"] = self.ui.iso_comboBox.currentText()
lab_info = self.add_laboratory_info() lab_info = self.add_laboratory_info()
user_data["image_description"] = f"{self.ui.image_description_comboBox.currentText()} {lab_info}" user_data["image_description"] = (
f"{self.ui.image_description_comboBox.currentText()} {lab_info}"
)
user_data["artist"] = self.ui.artist_comboBox.currentText() user_data["artist"] = self.ui.artist_comboBox.currentText()
user_data["copyright_info"] = self.ui.copyright_info_comboBox.currentText() user_data["copyright_info"] = self.ui.copyright_info_comboBox.currentText()
user_data["software"] = f"{self.name} {self.version} with {self.o.name} {self.o.version}" user_data["software"] = (
if int(self.ui.contrast_spinBox.text()) != 0 or int(self.ui.brightness_spinBox.text()) != 0: f"{self.name} {self.version} with {self.o.name} {self.o.version}"
user_data["user_comment"] = f"{self.ui.user_comment_comboBox.currentText()}, contrast: {self.ui.contrast_spinBox.text()}, brightness: {self.ui.brightness_spinBox.text()}" )
if (
int(self.ui.contrast_spinBox.text()) != 0
or int(self.ui.brightness_spinBox.text()) != 0
):
user_data["user_comment"] = (
f"{self.ui.user_comment_comboBox.currentText()}, contrast: {self.ui.contrast_spinBox.text()}, brightness: {self.ui.brightness_spinBox.text()}"
)
else: else:
user_data["user_comment"] = self.ui.user_comment_comboBox.currentText() user_data["user_comment"] = self.ui.user_comment_comboBox.currentText()
@ -477,13 +499,18 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
def get_selected_exif(self): def get_selected_exif(self):
"""Collect selected EXIF data and handle date and GPS if necessary.""" """Collect selected EXIF data and handle date and GPS if necessary."""
selected_exif = self.collect_selected_exif() if self.ui.exif_checkbox.isChecked() else None selected_exif = (
self.collect_selected_exif() if self.ui.exif_checkbox.isChecked() else None
)
if selected_exif: if selected_exif:
if self.ui.add_date_checkBox.isChecked(): if self.ui.add_date_checkBox.isChecked():
selected_exif["date_time_original"] = self.get_date() selected_exif["date_time_original"] = self.get_date()
if self.ui.gps_checkBox.isChecked(): if self.ui.gps_checkBox.isChecked():
try: try:
self.settings["gps"] = [float(self.ui.lat_lineEdit.text()), float(self.ui.long_lineEdit.text())] self.settings["gps"] = [
float(self.ui.lat_lineEdit.text()),
float(self.ui.long_lineEdit.text()),
]
except ValueError as e: except ValueError as e:
self.settings["gps"] = "Wrong gps data" self.settings["gps"] = "Wrong gps data"
else: else:
@ -503,22 +530,47 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
self.settings["output_folder"] = self.get_text_value(self.ui.output_path) self.settings["output_folder"] = self.get_text_value(self.ui.output_path)
self.settings["file_format"] = self.ui.image_type.currentText() self.settings["file_format"] = self.ui.image_type.currentText()
# Quality # Quality
self.settings["jpg_quality"] = self.get_spinbox_value(self.ui.jpg_quality_spinBox) self.settings["jpg_quality"] = self.get_spinbox_value(
self.settings["png_compression"] = self.get_spinbox_value(self.ui.png_quality_spinBox) self.ui.jpg_quality_spinBox
self.settings["resize"] = int(self.ui.resize_spinBox.text()) if self.ui.resize_spinBox.text() != "100" else None )
self.settings["png_compression"] = self.get_spinbox_value(
self.ui.png_quality_spinBox
)
self.settings["resize"] = (
int(self.ui.resize_spinBox.text())
if self.ui.resize_spinBox.text() != "100"
else None
)
self.settings["optimize"] = self.get_checkbox_value(self.ui.optimize_checkBox) self.settings["optimize"] = self.get_checkbox_value(self.ui.optimize_checkBox)
# Changes for image # Changes for image
self.settings["brightness"] = int(self.ui.brightness_spinBox.text()) if self.ui.brightness_spinBox.text() != "0" else None self.settings["brightness"] = (
self.settings["contrast"] = int(self.ui.contrast_spinBox.text()) if self.ui.contrast_spinBox.text() != "0" else None int(self.ui.brightness_spinBox.text())
if self.ui.brightness_spinBox.text() != "0"
else None
)
self.settings["contrast"] = (
int(self.ui.contrast_spinBox.text())
if self.ui.contrast_spinBox.text() != "0"
else None
)
self.settings["grayscale"] = self.get_checkbox_value(self.ui.grayscale_checkBox) self.settings["grayscale"] = self.get_checkbox_value(self.ui.grayscale_checkBox)
# Watermark # Watermark
self.settings["font_size"] = self.get_combobox_value(self.ui.font_size_comboBox) self.settings["font_size"] = self.get_combobox_value(self.ui.font_size_comboBox)
self.settings["watermark"] = self.get_text_value(self.ui.watermark_lineEdit) self.settings["watermark"] = self.get_text_value(self.ui.watermark_lineEdit)
# Naming # Naming
new_name = self.get_text_value(self.ui.filename, False) if self.ui.rename_checkbox.isChecked() else False new_name = (
if isinstance(new_name, str): new_name = new_name.replace(" ", "_") self.get_text_value(self.ui.filename, False)
if self.ui.rename_checkbox.isChecked()
else False
)
if isinstance(new_name, str):
new_name = new_name.replace(" ", "_")
self.settings["new_file_names"] = new_name self.settings["new_file_names"] = new_name
self.settings["invert_image_order"] = self.get_checkbox_value(self.ui.revert_checkbox) if new_name is not False else None self.settings["invert_image_order"] = (
self.get_checkbox_value(self.ui.revert_checkbox)
if new_name is not False
else None
)
# Handle EXIF data selection # Handle EXIF data selection
self.settings["copy_exif"] = self.get_checkbox_value(self.ui.exif_copy_checkBox) self.settings["copy_exif"] = self.get_checkbox_value(self.ui.exif_copy_checkBox)
self.settings["own_exif"] = self.get_checkbox_value(self.ui.exif_checkbox) self.settings["own_exif"] = self.get_checkbox_value(self.ui.exif_checkbox)
@ -550,11 +602,13 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):
QApplication.closeAllWindows() QApplication.closeAllWindows()
event.accept() event.accept()
class WorkerSignals(QObject): class WorkerSignals(QObject):
# ChatGPT # ChatGPT
progress = Signal(int) progress = Signal(int)
finished = Signal() finished = Signal()
class ImageProcessorRunnable(QRunnable): class ImageProcessorRunnable(QRunnable):
# ChatGPT gave rough function layout # ChatGPT gave rough function layout
def __init__(self, image_files, settings, progress_callback): def __init__(self, image_files, settings, progress_callback):
@ -573,27 +627,32 @@ class ImageProcessorRunnable(QRunnable):
for i, image_file in enumerate(self.image_files, start=1): for i, image_file in enumerate(self.image_files, start=1):
input_path = os.path.join(input_folder, image_file) input_path = os.path.join(input_folder, image_file)
if self.settings["new_file_names"] != False: if self.settings["new_file_names"] != False:
image_name = self.u.append_number_to_name(self.settings["new_file_names"], i, len(self.image_files), self.settings["invert_image_order"]) image_name = self.u.append_number_to_name(
self.settings["new_file_names"],
i,
len(self.image_files),
self.settings["invert_image_order"],
)
else: else:
image_name = os.path.splitext(image_file)[0] image_name = os.path.splitext(image_file)[0]
output_path = os.path.join(output_folder, image_name) output_path = os.path.join(output_folder, image_name)
self.o.process_and_save_image( self.o.process_and_save_image(
image_input_file = input_path, image_input_file=input_path,
image_output_file = output_path, image_output_file=output_path,
file_type = self.settings["file_format"], file_type=self.settings["file_format"],
quality = self.settings["jpg_quality"], quality=self.settings["jpg_quality"],
compressing = self.settings["png_compression"], compressing=self.settings["png_compression"],
optimize = self.settings["optimize"], optimize=self.settings["optimize"],
resize = self.settings["resize"], resize=self.settings["resize"],
watermark = self.settings["watermark"], watermark=self.settings["watermark"],
font_size = self.settings["font_size"], font_size=self.settings["font_size"],
grayscale = self.settings["grayscale"], grayscale=self.settings["grayscale"],
brightness = self.settings["brightness"], brightness=self.settings["brightness"],
contrast = self.settings["contrast"], contrast=self.settings["contrast"],
dict_for_exif = self.settings["user_selected_exif"], dict_for_exif=self.settings["user_selected_exif"],
gps = self.settings["gps"], gps=self.settings["gps"],
copy_exif = self.settings["copy_exif"] copy_exif=self.settings["copy_exif"],
) )
self.signals.progress.emit(int((i / len(self.image_files)) * 100)) self.signals.progress.emit(int((i / len(self.image_files)) * 100))

View file

@ -1,32 +1,20 @@
import sys
import os import os
import sys
from datetime import datetime from datetime import datetime
from PyPiUpdater import PyPiUpdater from PyPiUpdater import PyPiUpdater
from PySide6 import QtCore, QtWidgets
from PySide6.QtCore import QRegularExpression, Qt, QTimer
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QApplication, QMainWindow, QMessageBox
from OptimaLab35 import __version__ from OptimaLab35 import __version__
from .const import (
CONFIG_BASE_PATH
)
from .const import CONFIG_BASE_PATH
from .ui import resources_rc from .ui import resources_rc
from .utils.utility import Utilities
from .ui.settings_window import Ui_Settings_Window from .ui.settings_window import Ui_Settings_Window
from .utils.utility import Utilities
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): class SettingsWindow(QMainWindow, Ui_Settings_Window):
# Mixture of code by me, code/functions refactored by ChatGPT and code directly from ChatGPT # Mixture of code by me, code/functions refactored by ChatGPT and code directly from ChatGPT
@ -45,8 +33,12 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
self.optimalab35_localversion = optimalab35_localversion self.optimalab35_localversion = optimalab35_localversion
self.optima35_localversion = optima35_localversion self.optima35_localversion = optima35_localversion
# Create PyPiUpdater instances # Create PyPiUpdater instances
self.ppu_ol35 = PyPiUpdater("OptimaLab35", self.optimalab35_localversion, self.update_log_file) self.ppu_ol35 = PyPiUpdater(
self.ppu_o35 = PyPiUpdater("optima35", self.optima35_localversion, self.update_log_file) "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.ol35_last_state = self.ppu_ol35.get_last_state()
self.o35_last_state = self.ppu_o35.get_last_state() self.o35_last_state = self.ppu_o35.get_last_state()
# Track which packages need an update # Track which packages need an update
@ -68,7 +60,9 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
# Connect buttons to functions # Connect buttons to functions
self.ui.check_for_update_Button.clicked.connect(self.check_for_updates) 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.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.label_last_check.setText(
f"Last check: {self.time_to_string(self.ol35_last_state[0])}"
)
self.ui.dev_widget.setVisible(False) self.ui.dev_widget.setVisible(False)
# Timer for long press detection # Timer for long press detection
@ -79,20 +73,22 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
# Connect button press/release # Connect button press/release
self.ui.check_for_update_Button.pressed.connect(self.start_long_press) 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.check_for_update_Button.released.connect(self.cancel_long_press)
self.ui.label_5.setText('<li><a href="https://code.boxyfoxy.net/CodeByMrFinchum/OptimaLab35/src/branch/main/CHANGELOG.md">Changelog</a></li>') self.ui.label_5.setText(
'<li><a href="https://code.boxyfoxy.net/CodeByMrFinchum/OptimaLab35/wiki/Changelog">Changelog</a></li>'
)
self.ui.label_5.setOpenExternalLinks(True) self.ui.label_5.setOpenExternalLinks(True)
#settings related # settings related
self.load_settings_into_ui() self.load_settings_into_ui()
self.ui.reset_exif_Button.clicked.connect(self.ask_reset_exif) 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_close_Button.clicked.connect(self.save_and_close)
self.ui.save_and_restart_Button.clicked.connect(self.save_and_restart) self.ui.save_and_restart_Button.clicked.connect(self.save_and_restart)
if os.name == "nt": # Disable restart app when windows. if os.name == "nt": # Disable restart app when windows.
self.ui.save_and_restart_Button.setVisible(False) self.ui.save_and_restart_Button.setVisible(False)
self.ui.restart_checkBox.setChecked(False) self.ui.restart_checkBox.setChecked(False)
self.ui.restart_checkBox.setVisible(False) self.ui.restart_checkBox.setVisible(False)
# setting related # setting related
def load_settings_into_ui(self): def load_settings_into_ui(self):
"""Loads the settings into the UI elements.""" """Loads the settings into the UI elements."""
settings = self.app_settings settings = self.app_settings
@ -101,7 +97,9 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
pkg_available = settings["theme"]["theme_pkg"] pkg_available = settings["theme"]["theme_pkg"]
if pkg_available: if pkg_available:
index = self.ui.theme_selection_comboBox.findText(theme_mode, QtCore.Qt.MatchFlag.MatchExactly) index = self.ui.theme_selection_comboBox.findText(
theme_mode, QtCore.Qt.MatchFlag.MatchExactly
)
if index != -1: if index != -1:
self.ui.theme_selection_comboBox.setCurrentIndex(index) self.ui.theme_selection_comboBox.setCurrentIndex(index)
self.ui.enable_theme_checkBox.setChecked(use_custom_theme) self.ui.enable_theme_checkBox.setChecked(use_custom_theme)
@ -130,8 +128,12 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
self.ui.install_pkg_Button.setText("Try again?") self.ui.install_pkg_Button.setText("Try again?")
def save_settings(self): def save_settings(self):
self.app_settings["theme"]["mode"] = self.ui.theme_selection_comboBox.currentText() self.app_settings["theme"]["mode"] = (
self.app_settings["theme"]["use_custom_theme"] = self.ui.enable_theme_checkBox.isChecked() 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) self.u.save_settings(self.app_settings)
def save_and_close(self): def save_and_close(self):
@ -143,7 +145,9 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
msg.setIcon(QMessageBox.Icon.Question) msg.setIcon(QMessageBox.Icon.Question)
msg.setWindowTitle("Confirm Reset") msg.setWindowTitle("Confirm Reset")
msg.setText("Are you sure you want to restart the app?") msg.setText("Are you sure you want to restart the app?")
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) msg.setStandardButtons(
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
# Show the message box and wait for the user's response # Show the message box and wait for the user's response
response = msg.exec() response = msg.exec()
@ -162,7 +166,9 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
msg.setIcon(QMessageBox.Icon.Question) msg.setIcon(QMessageBox.Icon.Question)
msg.setWindowTitle("Confirm Reset") msg.setWindowTitle("Confirm Reset")
msg.setText("Are you sure you want to reset the EXIF options to default?") msg.setText("Are you sure you want to reset the EXIF options to default?")
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) msg.setStandardButtons(
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
# Show the message box and wait for the user's response # Show the message box and wait for the user's response
response = msg.exec() response = msg.exec()
@ -173,7 +179,7 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
else: else:
pass # Do nothing if "No" is selected pass # Do nothing if "No" is selected
# update related parts # update related parts
def start_long_press(self): def start_long_press(self):
"""Start the timer when button is pressed.""" """Start the timer when button is pressed."""
# brave AI # brave AI
@ -214,7 +220,9 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
def local_update(self): def local_update(self):
dist_folder = os.path.expanduser("~/.config/OptimaLab35/dist/") dist_folder = os.path.expanduser("~/.config/OptimaLab35/dist/")
packages_to_update = [pkg for pkg, update in self.updates_available.items() if update] packages_to_update = [
pkg for pkg, update in self.updates_available.items() if update
]
if not packages_to_update: if not packages_to_update:
QMessageBox.information(self, "Update", "No updates available.") QMessageBox.information(self, "Update", "No updates available.")
@ -243,7 +251,9 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
elif package == "optima35": elif package == "optima35":
pkg_info = self.ppu_o35.update_from_local(dist_folder) 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]}") update_results.append(
f"{package}: {'Success' if pkg_info[0] else 'Failed'}\n{pkg_info[1]}"
)
# Show summary of updates # Show summary of updates
# Show update completion message # Show update completion message
@ -302,7 +312,9 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
def update_and_restart(self): def update_and_restart(self):
"""Update selected packages and restart the application.""" """Update selected packages and restart the application."""
packages_to_update = [pkg for pkg, update in self.updates_available.items() if update] packages_to_update = [
pkg for pkg, update in self.updates_available.items() if update
]
if not packages_to_update: if not packages_to_update:
QMessageBox.information(self, "Update", "No updates available.") QMessageBox.information(self, "Update", "No updates available.")
@ -331,7 +343,9 @@ class SettingsWindow(QMainWindow, Ui_Settings_Window):
elif package == "optima35": elif package == "optima35":
pkg_info = self.ppu_o35.update_package() pkg_info = self.ppu_o35.update_package()
update_results.append(f"{package}: {'Success' if pkg_info[0] else 'Failed'}\n{pkg_info[1]}") update_results.append(
f"{package}: {'Success' if pkg_info[0] else 'Failed'}\n{pkg_info[1]}"
)
# Show summary of updates # Show summary of updates
# Show update completion message # Show update completion message