From 2d89c95a231dcf92df79f5b14e15ca61d7993429 Mon Sep 17 00:00:00 2001 From: Louis Mazin Date: Fri, 7 Nov 2025 11:26:14 +0100 Subject: [PATCH] fix some issues --- BUILD.spec | 2 +- app/ui/widgets/drag_drop_frame.py | 2 +- app/ui/windows/export_window.py | 98 +++++++++++++++++++++++++++---- tools/build.bat | 43 ++++++++++++-- tools/build.command | 59 ------------------- tools/open.command | 59 ------------------- 6 files changed, 126 insertions(+), 137 deletions(-) delete mode 100644 tools/build.command delete mode 100644 tools/open.command diff --git a/BUILD.spec b/BUILD.spec index 4b02db2..81a6ed1 100644 --- a/BUILD.spec +++ b/BUILD.spec @@ -18,7 +18,7 @@ os_name = config.get("app_os", sys.platform) app_name = config.get("app_name", "Application") # --- Construct dynamic name --- -name = f"{app_name}-{os_name}-{arch}-v{version}" +name = f"{app_name}" # --- Optional icon path --- icon = getenv("ICON_PATH", "") diff --git a/app/ui/widgets/drag_drop_frame.py b/app/ui/widgets/drag_drop_frame.py index 5f92dd0..8d856ee 100644 --- a/app/ui/widgets/drag_drop_frame.py +++ b/app/ui/widgets/drag_drop_frame.py @@ -32,7 +32,7 @@ class DragDropFrame(QFrame): urls = event.mimeData().urls() if urls and self.parent_window: file_path = urls[0].toLocalFile() - self.parent_window.set_dicom_from_files(file_path) + self.parent_window.find_dicoms_from_files(file_path) def getDragIndicator(self) -> QLabel: drag_indicator = QLabel(self) diff --git a/app/ui/windows/export_window.py b/app/ui/windows/export_window.py index f0b382e..bf55dda 100644 --- a/app/ui/windows/export_window.py +++ b/app/ui/windows/export_window.py @@ -128,6 +128,11 @@ class ExportWindow(QWidget): # disable automatic stretch and fit col 1 to its contents tree.header().setStretchLastSection(False) tree.header().setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents) + + # Install event filter to handle clicks on items + tree.viewport().installEventFilter(self) + self._current_tree = tree # Store reference for event filter + popup.layout().addWidget(tree) for dicom, sub_dicoms in dicom_list: @@ -188,8 +193,9 @@ class ExportWindow(QWidget): self.show_color_dialog(item, btn, cols)) tree.setItemWidget(child_item, 1, color_button) - # single connection to handle both directions + # Connect signals - itemChanged handles all checkbox state changes tree.itemChanged.connect(self.on_item_changed) + tree.resizeColumnToContents(0) # Resize first column to fit content tree.setColumnWidth(0, max(200, tree.columnWidth(0))) # Ensure minimum 200px for first column tree.setColumnWidth(1, 20) # Exact width for button @@ -202,17 +208,54 @@ class ExportWindow(QWidget): popup.layout().addWidget(confirm_button) popup.exec() + + # Clean up reference + self._current_tree = None - def toggle_child_items(self, item): - if item.childCount() > 0: # Check if the item has children - for i in range(item.childCount()): - child = item.child(i) - child.setCheckState(0, item.checkState(0)) # Set child state to match parent state + def eventFilter(self, source, event): + # Handle tree widget clicks + if hasattr(self, '_current_tree') and self._current_tree and source == self._current_tree.viewport(): + if event.type() == QEvent.Type.MouseButtonPress and event.button() == Qt.MouseButton.LeftButton: + pos = event.pos() + item = self._current_tree.itemAt(pos) + + if item: + # Get the column that was clicked + column = self._current_tree.header().logicalIndexAt(pos.x()) + if column == 0: # Only on first column + # Get the visual rect for the item + visual_rect = self._current_tree.visualItemRect(item) + + # Calculate the indentation and branch indicator area + # The branch indicator (arrow) is typically in the first ~20 pixels + indent = self._current_tree.indentation() + item_depth = 0 + parent = item.parent() + while parent: + item_depth += 1 + parent = parent.parent() + + # Calculate where the branch indicator starts + branch_start = item_depth * indent + branch_end = branch_start + indent + + # If click is NOT in the branch indicator area, toggle checkbox + if pos.x() < branch_start or pos.x() > branch_end: + current_state = item.checkState(0) + new_state = Qt.CheckState.Unchecked if current_state == Qt.CheckState.Checked else Qt.CheckState.Checked + item.setCheckState(0, new_state) + return True # Event handled + + # Handle combobox wheel events + if isinstance(source, QComboBox) and event.type() == QEvent.Type.Wheel: + return True + + return super().eventFilter(source, event) def show_color_dialog(self, item, button, colors): dialog = QDialog(self) dialog.setWindowFlags(Qt.WindowType.Popup) - dialog.setFixedSize(200, 40) # Increased height for labels + dialog.setFixedSize(200, 20) # Reduced height since no labels # Position dialog to the left of the button button_pos = button.mapToGlobal(button.rect().topLeft()) @@ -237,12 +280,6 @@ class ExportWindow(QWidget): color_btn.setToolTip(ExportCategory.get_name(color)) color_btn.clicked.connect(lambda _, c=color: self.select_color(item, button, c, dialog)) layout.addWidget(color_btn, 0, i) - - # Add label below button - label = QLabel(ExportCategory.get_name(color)[:3]) # First 3 letters - label.setAlignment(Qt.AlignmentFlag.AlignCenter) - label.setStyleSheet("font-size: 8px; color: black;") - layout.addWidget(label, 1, i) dialog.exec() @@ -338,8 +375,43 @@ class ExportWindow(QWidget): self.alert_manager.show_error("export_error") def eventFilter(self, source, event): + # Handle tree widget clicks + if hasattr(self, '_current_tree') and self._current_tree and source == self._current_tree.viewport(): + if event.type() == QEvent.Type.MouseButtonPress and event.button() == Qt.MouseButton.LeftButton: + pos = event.pos() + item = self._current_tree.itemAt(pos) + + if item: + # Get the column that was clicked + column = self._current_tree.header().logicalIndexAt(pos.x()) + if column == 0: # Only on first column + # Get the visual rect for the item + visual_rect = self._current_tree.visualItemRect(item) + + # Calculate the indentation and branch indicator area + # The branch indicator (arrow) is typically in the first ~20 pixels + indent = self._current_tree.indentation() + item_depth = 0 + parent = item.parent() + while parent: + item_depth += 1 + parent = parent.parent() + + # Calculate where the branch indicator starts + branch_start = item_depth * indent + branch_end = branch_start + indent + + # If click is NOT in the branch indicator area, toggle checkbox + if pos.x() < branch_start or pos.x() > branch_end: + current_state = item.checkState(0) + new_state = Qt.CheckState.Unchecked if current_state == Qt.CheckState.Checked else Qt.CheckState.Checked + item.setCheckState(0, new_state) + return True # Event handled + + # Handle combobox wheel events if isinstance(source, QComboBox) and event.type() == QEvent.Type.Wheel: return True + return super().eventFilter(source, event) def on_item_changed(self, item, column): diff --git a/tools/build.bat b/tools/build.bat index 6d21702..05c661b 100644 --- a/tools/build.bat +++ b/tools/build.bat @@ -4,6 +4,7 @@ setlocal enabledelayedexpansion REM === PATH SETUP === set PARENT_DIR=%~dp0.. set CONFIG_FILE=%PARENT_DIR%\config.json +set ICON_FILE=%PARENT_DIR%\data\assets\icon.png set ENV_FILE=%PARENT_DIR%\.env REM Check if .env file exists @@ -24,8 +25,10 @@ REM === Extract python path from .env file === for /f "usebackq tokens=2 delims==" %%i in (`findstr "PYTHON_PATH" "%ENV_FILE%"`) do set SYSTEM_PYTHON=%%i set VENV_PATH=%PARENT_DIR%\WINenv_%ARCHITECTURE% -set EXE_NAME=%APP_NAME%-Windows-%ARCHITECTURE% +set EXE_NAME=%APP_NAME%.exe set PYTHON_IN_VENV=%VENV_PATH%\Scripts\python.exe +set BUILD_DIR=%PARENT_DIR%\build +set ZIP_FILE=%BUILD_DIR%\%APP_NAME%.zip REM === Verify Python existence === if not exist "%SYSTEM_PYTHON%" ( @@ -45,12 +48,44 @@ if not exist "%VENV_PATH%\Scripts\activate.bat" ( REM === Run PyInstaller === "%PYTHON_IN_VENV%" -m PyInstaller ^ - --distpath "%PARENT_DIR%\build" ^ - --workpath "%PARENT_DIR%\build\dist" ^ + --distpath "%BUILD_DIR%" ^ + --workpath "%BUILD_DIR%\dist" ^ --clean ^ "%PARENT_DIR%\BUILD.spec" REM === Clean build cache === -rmdir /s /q "%PARENT_DIR%\build\dist" +rmdir /s /q "%BUILD_DIR%\dist" + +REM === Create ZIP === +echo [INFO] Creating ZIP archive... + +set TEMP_ZIP_DIR=%BUILD_DIR%\temp_zip + +REM Remove old temp dir if exists +if exist "%TEMP_ZIP_DIR%" rmdir /s /q "%TEMP_ZIP_DIR%" +mkdir "%TEMP_ZIP_DIR%" + +REM Copy compiled app - tout le contenu du build sauf les ZIP existants +move /Y "%BUILD_DIR%\%EXE_NAME%" "%TEMP_ZIP_DIR%\" + +REM Copy config.json +copy "%CONFIG_FILE%" "%TEMP_ZIP_DIR%\" /Y + +REM Copy icon.png +copy "%ICON_FILE%" "%TEMP_ZIP_DIR%\" /Y + +REM Copy data/lang +xcopy /E /I /Y "%PARENT_DIR%\data\lang" "%TEMP_ZIP_DIR%\lang" + +REM Remove old ZIP if exists +if exist "%ZIP_FILE%" del "%ZIP_FILE%" + +REM Create ZIP +powershell -NoProfile -Command "Add-Type -AssemblyName 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::CreateFromDirectory('%TEMP_ZIP_DIR%', '%ZIP_FILE%')" + +REM Remove temp folder +rmdir /s /q "%TEMP_ZIP_DIR%" + +echo [INFO] ZIP created at: %ZIP_FILE% endlocal diff --git a/tools/build.command b/tools/build.command deleted file mode 100644 index 69841f9..0000000 --- a/tools/build.command +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -set -e - -# === PATH SETUP === -PARENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -CONFIG_FILE="$PARENT_DIR/config.json" -ENV_FILE="$PARENT_DIR/.env" - -# --- Check .env file --- -if [[ ! -f "$ENV_FILE" ]]; then - echo "[ERROR] .env file not found. Please copy .env.example to .env and configure it." - exit 1 -fi - -# --- Check jq availability --- -if ! command -v jq &>/dev/null; then - echo "[ERROR] 'jq' is required. Install it with: brew install jq" - exit 1 -fi - -# --- Extract values from config.json --- -ICON_PATH=$(jq -r '.icon_path' "$CONFIG_FILE") -APP_NAME=$(jq -r '.app_name' "$CONFIG_FILE") -ARCHITECTURE=$(jq -r '.architecture' "$CONFIG_FILE") - -# --- Extract PYTHON_PATH from .env --- -SYSTEM_PYTHON=$(grep -E "^PYTHON_PATH=" "$ENV_FILE" | cut -d '=' -f2) - -VENV_PATH="$PARENT_DIR/MACenv_$ARCHITECTURE" -EXE_NAME="${APP_NAME}-MacOS-${ARCHITECTURE}" -PYTHON_IN_VENV="$VENV_PATH/bin/python" - -# --- Verify Python existence --- -if [[ ! -x "$SYSTEM_PYTHON" ]]; then - echo "[ERROR] Python not found at: $SYSTEM_PYTHON" - exit 1 -fi - -# --- Check if virtual environment exists --- -if [[ ! -f "$VENV_PATH/bin/activate" ]]; then - echo "[INFO] Virtual environment not found. Creating..." - "$SYSTEM_PYTHON" -m venv "$VENV_PATH" - "$PYTHON_IN_VENV" -m pip install --upgrade pip - "$PYTHON_IN_VENV" -m pip install -r "$PARENT_DIR/requirements.txt" -else - echo "[INFO] Virtual environment found." -fi - -# --- Run PyInstaller --- -"$PYTHON_IN_VENV" -m PyInstaller \ - --distpath "$PARENT_DIR/build" \ - --workpath "$PARENT_DIR/build/dist" \ - --clean \ - "$PARENT_DIR/BUILD.spec" - -# --- Clean build cache --- -rm -rf "$PARENT_DIR/build/dist" - -echo "[INFO] Build complete: $EXE_NAME" \ No newline at end of file diff --git a/tools/open.command b/tools/open.command deleted file mode 100644 index 675450f..0000000 --- a/tools/open.command +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -set -e - -# Root paths -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -CONFIG_FILE="$ROOT_DIR/config.json" -REQUIREMENTS="$ROOT_DIR/requirements.txt" -ENV_FILE="$ROOT_DIR/.env" - -# Check if .env exists -if [[ ! -f "$ENV_FILE" ]]; then - echo "[ERROR] .env file not found. Please copy .env.example to .env and configure it." - exit 1 -fi - -# Extract architecture from config.json (requires jq) -if ! command -v jq &>/dev/null; then - echo "[ERROR] 'jq' is required. Install it with: brew install jq" - exit 1 -fi -ARCHITECTURE=$(jq -r '.architecture' "$CONFIG_FILE") - -# Extract python path from .env -PYTHON_EXEC=$(grep -E "^PYTHON_PATH=" "$ENV_FILE" | cut -d '=' -f2) - -# Construct venv path -ENV_NAME="MACenv_$ARCHITECTURE" -ENV_PATH="$ROOT_DIR/$ENV_NAME" - -# Check python executable -if [[ ! -x "$PYTHON_EXEC" ]]; then - echo "[ERROR] Python not found at: $PYTHON_EXEC" - echo "Please check your .env or installation path." - exit 1 -fi - -# Show info -echo "[INFO] Configuration:" -echo " Python: $PYTHON_EXEC" -echo " Env: $ENV_NAME" - -# Create virtual env if missing -if [[ ! -d "$ENV_PATH/bin" ]]; then - echo "[INFO] Virtual environment not found, creating..." - "$PYTHON_EXEC" -m venv "$ENV_PATH" - echo "[INFO] Installing dependencies..." - "$ENV_PATH/bin/python" -m pip install --upgrade pip - "$ENV_PATH/bin/pip" install -r "$REQUIREMENTS" -else - echo "[INFO] Virtual environment found." -fi - -# Activate and launch VS Code -echo "[INFO] Launching VS Code..." -# shellcheck source=/dev/null -source "$ENV_PATH/bin/activate" -open -a "Visual Studio Code" "$ROOT_DIR" - -exit 0 \ No newline at end of file