generated from LouisMazin/PythonApplicationTemplate
fix some issues
This commit is contained in:
parent
a9dfbee1a8
commit
2d89c95a23
@ -18,7 +18,7 @@ os_name = config.get("app_os", sys.platform)
|
|||||||
app_name = config.get("app_name", "Application")
|
app_name = config.get("app_name", "Application")
|
||||||
|
|
||||||
# --- Construct dynamic name ---
|
# --- Construct dynamic name ---
|
||||||
name = f"{app_name}-{os_name}-{arch}-v{version}"
|
name = f"{app_name}"
|
||||||
|
|
||||||
# --- Optional icon path ---
|
# --- Optional icon path ---
|
||||||
icon = getenv("ICON_PATH", "")
|
icon = getenv("ICON_PATH", "")
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class DragDropFrame(QFrame):
|
|||||||
urls = event.mimeData().urls()
|
urls = event.mimeData().urls()
|
||||||
if urls and self.parent_window:
|
if urls and self.parent_window:
|
||||||
file_path = urls[0].toLocalFile()
|
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:
|
def getDragIndicator(self) -> QLabel:
|
||||||
drag_indicator = QLabel(self)
|
drag_indicator = QLabel(self)
|
||||||
|
|||||||
@ -128,6 +128,11 @@ class ExportWindow(QWidget):
|
|||||||
# disable automatic stretch and fit col 1 to its contents
|
# disable automatic stretch and fit col 1 to its contents
|
||||||
tree.header().setStretchLastSection(False)
|
tree.header().setStretchLastSection(False)
|
||||||
tree.header().setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
|
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)
|
popup.layout().addWidget(tree)
|
||||||
|
|
||||||
for dicom, sub_dicoms in dicom_list:
|
for dicom, sub_dicoms in dicom_list:
|
||||||
@ -188,8 +193,9 @@ class ExportWindow(QWidget):
|
|||||||
self.show_color_dialog(item, btn, cols))
|
self.show_color_dialog(item, btn, cols))
|
||||||
tree.setItemWidget(child_item, 1, color_button)
|
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.itemChanged.connect(self.on_item_changed)
|
||||||
|
|
||||||
tree.resizeColumnToContents(0) # Resize first column to fit content
|
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(0, max(200, tree.columnWidth(0))) # Ensure minimum 200px for first column
|
||||||
tree.setColumnWidth(1, 20) # Exact width for button
|
tree.setColumnWidth(1, 20) # Exact width for button
|
||||||
@ -202,17 +208,54 @@ class ExportWindow(QWidget):
|
|||||||
popup.layout().addWidget(confirm_button)
|
popup.layout().addWidget(confirm_button)
|
||||||
|
|
||||||
popup.exec()
|
popup.exec()
|
||||||
|
|
||||||
|
# Clean up reference
|
||||||
|
self._current_tree = None
|
||||||
|
|
||||||
def toggle_child_items(self, item):
|
def eventFilter(self, source, event):
|
||||||
if item.childCount() > 0: # Check if the item has children
|
# Handle tree widget clicks
|
||||||
for i in range(item.childCount()):
|
if hasattr(self, '_current_tree') and self._current_tree and source == self._current_tree.viewport():
|
||||||
child = item.child(i)
|
if event.type() == QEvent.Type.MouseButtonPress and event.button() == Qt.MouseButton.LeftButton:
|
||||||
child.setCheckState(0, item.checkState(0)) # Set child state to match parent state
|
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):
|
def show_color_dialog(self, item, button, colors):
|
||||||
dialog = QDialog(self)
|
dialog = QDialog(self)
|
||||||
dialog.setWindowFlags(Qt.WindowType.Popup)
|
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
|
# Position dialog to the left of the button
|
||||||
button_pos = button.mapToGlobal(button.rect().topLeft())
|
button_pos = button.mapToGlobal(button.rect().topLeft())
|
||||||
@ -237,12 +280,6 @@ class ExportWindow(QWidget):
|
|||||||
color_btn.setToolTip(ExportCategory.get_name(color))
|
color_btn.setToolTip(ExportCategory.get_name(color))
|
||||||
color_btn.clicked.connect(lambda _, c=color: self.select_color(item, button, c, dialog))
|
color_btn.clicked.connect(lambda _, c=color: self.select_color(item, button, c, dialog))
|
||||||
layout.addWidget(color_btn, 0, i)
|
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()
|
dialog.exec()
|
||||||
|
|
||||||
@ -338,8 +375,43 @@ class ExportWindow(QWidget):
|
|||||||
self.alert_manager.show_error("export_error")
|
self.alert_manager.show_error("export_error")
|
||||||
|
|
||||||
def eventFilter(self, source, event):
|
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:
|
if isinstance(source, QComboBox) and event.type() == QEvent.Type.Wheel:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return super().eventFilter(source, event)
|
return super().eventFilter(source, event)
|
||||||
|
|
||||||
def on_item_changed(self, item, column):
|
def on_item_changed(self, item, column):
|
||||||
|
|||||||
@ -4,6 +4,7 @@ setlocal enabledelayedexpansion
|
|||||||
REM === PATH SETUP ===
|
REM === PATH SETUP ===
|
||||||
set PARENT_DIR=%~dp0..
|
set PARENT_DIR=%~dp0..
|
||||||
set CONFIG_FILE=%PARENT_DIR%\config.json
|
set CONFIG_FILE=%PARENT_DIR%\config.json
|
||||||
|
set ICON_FILE=%PARENT_DIR%\data\assets\icon.png
|
||||||
set ENV_FILE=%PARENT_DIR%\.env
|
set ENV_FILE=%PARENT_DIR%\.env
|
||||||
|
|
||||||
REM Check if .env file exists
|
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
|
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 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 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 ===
|
REM === Verify Python existence ===
|
||||||
if not exist "%SYSTEM_PYTHON%" (
|
if not exist "%SYSTEM_PYTHON%" (
|
||||||
@ -45,12 +48,44 @@ if not exist "%VENV_PATH%\Scripts\activate.bat" (
|
|||||||
|
|
||||||
REM === Run PyInstaller ===
|
REM === Run PyInstaller ===
|
||||||
"%PYTHON_IN_VENV%" -m PyInstaller ^
|
"%PYTHON_IN_VENV%" -m PyInstaller ^
|
||||||
--distpath "%PARENT_DIR%\build" ^
|
--distpath "%BUILD_DIR%" ^
|
||||||
--workpath "%PARENT_DIR%\build\dist" ^
|
--workpath "%BUILD_DIR%\dist" ^
|
||||||
--clean ^
|
--clean ^
|
||||||
"%PARENT_DIR%\BUILD.spec"
|
"%PARENT_DIR%\BUILD.spec"
|
||||||
|
|
||||||
REM === Clean build cache ===
|
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
|
endlocal
|
||||||
|
|||||||
@ -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"
|
|
||||||
@ -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
|
|
||||||
Loading…
x
Reference in New Issue
Block a user