Skip to content

Commit 378fb59

Browse files
committed
Refactor workspace management in Core/Gui.py and related modules
1 parent 1520f4b commit 378fb59

4 files changed

Lines changed: 591 additions & 337 deletions

File tree

Core/Gui.py

Lines changed: 22 additions & 325 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-License-Identifier: Apache-2.0
1+
# SPDX-License-Identifier: Apache-2.0
22
# Copyright 2026 Ague Samuel Amen
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,6 +35,10 @@
3535
show_language_dialog as _i18n_show_dialog,
3636
)
3737

38+
# Import des classes de gestion du workspace
39+
from Core.WorkSpaceManager.SetupWorkspace import SetupWorkspace
40+
from Core.WorkSpaceManager.WorkspaceAdvancedManipulation import WorkspaceAdvancedManipulation
41+
3842

3943
def get_selected_workspace() -> Optional[str]:
4044
"""Retourne le workspace sélectionné d'une manière non bloquante et thread-safe."""
@@ -139,223 +143,26 @@ def _apply_label(tr):
139143
from .UiConnection import init_ui
140144

141145
def dragEnterEvent(self, event: QDropEvent):
142-
if event.mimeData().hasUrls():
143-
event.acceptProposedAction()
144-
else:
145-
event.ignore()
146+
"""Gère l'événement dragEnter en déléguant à WorkspaceAdvancedManipulation."""
147+
WorkspaceAdvancedManipulation.handle_drag_enter_event(self, event)
146148

147149
def dropEvent(self, event: QDropEvent):
148-
urls = event.mimeData().urls()
149-
added = 0
150-
for url in urls:
151-
path = url.toLocalFile()
152-
if os.path.isdir(path):
153-
added += self.add_py_files_from_folder(path)
154-
elif path.endswith(".py"):
155-
# Vérifie que le fichier est dans workspace (si défini)
156-
if (
157-
self.workspace_dir
158-
and not os.path.commonpath([path, self.workspace_dir])
159-
== self.workspace_dir
160-
):
161-
self.log_i18n(
162-
f"⚠️ Ignoré (hors workspace): {path}",
163-
f"⚠️ Ignored (outside workspace): {path}",
164-
)
165-
continue
166-
if path not in self.python_files:
167-
self.python_files.append(path)
168-
relative_path = (
169-
os.path.relpath(path, self.workspace_dir)
170-
if self.workspace_dir
171-
else path
172-
)
173-
self.file_list.addItem(relative_path)
174-
added += 1
175-
self.log_i18n(
176-
f"✅ {added} fichier(s) ajouté(s) via drag & drop.",
177-
f"✅ {added} file(s) added via drag & drop.",
178-
)
179-
self.update_command_preview()
150+
"""Gère l'événement drop en déléguant à WorkspaceAdvancedManipulation."""
151+
WorkspaceAdvancedManipulation.handle_drop_event(self, event)
180152

181153
def add_py_files_from_folder(self, folder):
182-
from Core.ArkConfigManager import load_ark_config, should_exclude_file
183-
184-
count = 0
185-
excluded_count = 0
186-
# Charger la configuration ARK pour les patterns d'exclusion
187-
ark_config = load_ark_config(self.workspace_dir)
188-
exclusion_patterns = ark_config.get("exclusion_patterns", [])
189-
190-
for root, _, files in os.walk(folder):
191-
for f in files:
192-
if f.endswith(".py"):
193-
full_path = os.path.join(root, f)
194-
if (
195-
self.workspace_dir
196-
and not os.path.commonpath([full_path, self.workspace_dir])
197-
== self.workspace_dir
198-
):
199-
continue
200-
201-
# Vérifier les patterns d'exclusion depuis ARK_Main_Config.yml
202-
if should_exclude_file(
203-
full_path, self.workspace_dir, exclusion_patterns
204-
):
205-
excluded_count += 1
206-
continue
207-
208-
if full_path not in self.python_files:
209-
self.python_files.append(full_path)
210-
relative_path = (
211-
os.path.relpath(full_path, self.workspace_dir)
212-
if self.workspace_dir
213-
else full_path
214-
)
215-
self.file_list.addItem(relative_path)
216-
count += 1
217-
218-
# Afficher un message récPluginstulatif si des fichiers ont été exclus
219-
if excluded_count > 0:
220-
self.log_i18n(
221-
f"⏩ Exclusion appliquée : {excluded_count} fichier(s) exclu(s) selon ARK_Main_Config.yml",
222-
f"⏩ Exclusion applied: {excluded_count} file(s) excluded according to ARK_Main_Config.yml",
223-
)
224-
225-
return count
154+
"""Ajoute les fichiers Python du dossier en déléguant à SetupWorkspace."""
155+
return SetupWorkspace.add_py_files_from_folder(self, folder)
226156

227157
def select_workspace(self):
228-
folder = QFileDialog.getExistingDirectory(self, "Choisir le dossier du projet")
158+
"""Ouvre une boîte de dialogue pour sélectionner le workspace."""
159+
folder = SetupWorkspace.select_workspace(self)
229160
if folder:
230161
self.apply_workspace_selection(folder, source="ui")
231162

232163
def apply_workspace_selection(self, folder: str, source: str = "ui") -> bool:
233-
try:
234-
# Afficher le dialog de chargement du workspace
235-
try:
236-
loading_dialog = CompilationProcessDialog(
237-
"Chargement de l'espace de travail", self
238-
)
239-
loading_dialog.set_status("📁 Chargement de l'espace de travail...")
240-
loading_dialog.btn_cancel.setEnabled(False)
241-
loading_dialog.show()
242-
QApplication.processEvents()
243-
except Exception:
244-
loading_dialog = None
245-
246-
# Ensure target folder exists; auto-create if missing; never refuse
247-
if not folder:
248-
try:
249-
self.log_i18n(
250-
"⚠️ Chemin de workspace vide fourni; aucune modification appliquée (accepté).",
251-
"⚠️ Empty workspace path provided; no changes applied (accepted).",
252-
)
253-
except Exception:
254-
pass
255-
try:
256-
if loading_dialog:
257-
loading_dialog.close()
258-
except Exception:
259-
pass
260-
return True
261-
if not os.path.isdir(folder):
262-
try:
263-
os.makedirs(folder, exist_ok=True)
264-
try:
265-
self.log_i18n(
266-
f"📁 Dossier cré�� automatiquement: {folder}",
267-
f"📁 Folder created automatically: {folder}",
268-
)
269-
except Exception:
270-
pass
271-
except Exception:
272-
try:
273-
self.log_i18n(
274-
f"⚠️ Impossible de créer le dossier, poursuite quand même: {folder}",
275-
f"⚠️ Unable to create folder, continuing anyway: {folder}",
276-
)
277-
except Exception:
278-
pass
279-
# Confirmation when Plugins requests workspace change
280-
if str(source).lower() == "plugin":
281-
# Auto-approve Plugins workspace switch; cancel running builds if any
282-
try:
283-
if getattr(self, "processes", None) and self.processes:
284-
try:
285-
self.log_i18n(
286-
"⛔ Arrêt des compilations en cours pour changer de workspace (Plugins).",
287-
"⛔ Stopping ongoing builds to switch workspace (Plugins).",
288-
)
289-
except Exception:
290-
pass
291-
try:
292-
self.cancel_all_compilations()
293-
except Exception:
294-
pass
295-
except Exception:
296-
pass
297-
else:
298-
# Non-Plugins requests: never refuse; cancel running builds if any
299-
if getattr(self, "processes", None) and self.processes:
300-
try:
301-
self.log_i18n(
302-
"⛔ Arrêt des compilations en cours pour changer de workspace (UI).",
303-
"⛔ Stopping ongoing builds to switch workspace (UI).",
304-
)
305-
except Exception:
306-
pass
307-
try:
308-
self.cancel_all_compilations()
309-
except Exception:
310-
pass
311-
self.workspace_dir = folder
312-
try:
313-
global _workspace_dir_cache
314-
with _workspace_dir_lock:
315-
_workspace_dir_cache = folder
316-
except Exception:
317-
pass
318-
self.label_folder.setText(f"Dossier sélectionné : {folder}")
319-
self.python_files.clear()
320-
self.file_list.clear()
321-
self.add_py_files_from_folder(folder)
322-
self.selected_files.clear()
323-
self.update_command_preview()
324-
try:
325-
self.save_preferences()
326-
except Exception:
327-
pass
328-
# -- Configuration centralisée du workspace --
329-
try:
330-
self.venv_manager.setup_workspace(folder)
331-
except Exception as e:
332-
self.log_i18n(
333-
f"⚠️ Erreur lors de la configuration du workspace: {e}",
334-
f"⚠️ Error during workspace setup: {e}",
335-
)
336-
337-
# Fermer le dialog de chargement
338-
try:
339-
if loading_dialog:
340-
loading_dialog.close()
341-
except Exception:
342-
pass
343-
344-
return True
345-
except Exception as _e:
346-
try:
347-
self.log_i18n(
348-
f"❌ Échec application workspace: {_e}",
349-
f"❌ Failed to apply workspace: {_e}",
350-
)
351-
except Exception:
352-
pass
353-
try:
354-
if loading_dialog:
355-
loading_dialog.close()
356-
except Exception:
357-
pass
358-
return False
164+
"""Applique la sélection du workspace en déléguant à SetupWorkspace."""
165+
return SetupWorkspace.apply_workspace_selection(self, folder, source)
359166

360167
def select_venv_manually(self):
361168
self.venv_manager.select_venv_manually()
@@ -367,106 +174,12 @@ def install_requirements_if_needed(self, path):
367174
self.venv_manager.install_requirements_if_needed(path)
368175

369176
def select_files_manually(self):
370-
if not self.workspace_dir:
371-
QMessageBox.warning(
372-
self,
373-
self.tr("Attention", "Warning"),
374-
self.tr(
375-
"Veuillez d'abord sélectionner un dossier workspace.",
376-
"Please select a workspace folder first.",
377-
),
378-
)
379-
return
380-
files, _ = QFileDialog.getOpenFileNames(
381-
self,
382-
"Sélectionner des fichiers Python",
383-
self.workspace_dir,
384-
"Python Files (*.py)",
385-
)
386-
if files:
387-
valid_files = []
388-
for f in files:
389-
if os.path.commonpath([f, self.workspace_dir]) == self.workspace_dir:
390-
valid_files.append(f)
391-
else:
392-
QMessageBox.warning(
393-
self,
394-
self.tr("Fichier hors workspace", "File outside workspace"),
395-
self.tr(
396-
f"Le fichier {f} est en dehors du workspace et sera ignoré.",
397-
f"The file {f} is outside the workspace and will be ignored.",
398-
),
399-
)
400-
if valid_files:
401-
self.selected_files = valid_files
402-
self.log_i18n(
403-
f"✅ {len(valid_files)} fichier(s) sélectionné(s) manuellement.\n",
404-
f"✅ {len(valid_files)} file(s) selected manually.\n",
405-
)
406-
self.update_command_preview()
177+
"""Ouvre une boîte de dialogue pour sélectionner des fichiers en déléguant à WorkspaceAdvancedManipulation."""
178+
WorkspaceAdvancedManipulation.select_files_manually(self)
407179

408180
def open_ark_config(self):
409-
"""Ouvre le fichier ARK_Main_Config.yml dans l'éditeur par défaut"""
410-
if not self.workspace_dir:
411-
QMessageBox.warning(
412-
self,
413-
self.tr("Attention", "Warning"),
414-
self.tr(
415-
"Veuillez d'abord sélectionner un dossier workspace.",
416-
"Please select a workspace folder first.",
417-
),
418-
)
419-
return
420-
421-
config_path = os.path.join(self.workspace_dir, "ARK_Main_Config.yml")
422-
423-
# Créer le fichier s'il n'existe pas
424-
if not os.path.exists(config_path):
425-
try:
426-
from Core.ArkConfigManager import create_default_ark_config
427-
428-
if create_default_ark_config(self.workspace_dir):
429-
self.log_i18n(
430-
"📋 Fichier ARK_Main_Config.yml créé.",
431-
"📋 ARK_Main_Config.yml file created.",
432-
)
433-
except Exception as e:
434-
QMessageBox.critical(
435-
self,
436-
self.tr("Erreur", "Error"),
437-
self.tr(
438-
f"Impossible de créer ARK_Main_Config.yml: {e}",
439-
f"Failed to create ARK_Main_Config.yml: {e}",
440-
),
441-
)
442-
return
443-
444-
# Ouvrir le fichier dans l'éditeur par défaut
445-
try:
446-
import subprocess
447-
import platform
448-
449-
system = platform.system()
450-
if system == "Windows":
451-
os.startfile(config_path)
452-
elif system == "Darwin": # macOS
453-
subprocess.run(["open", config_path])
454-
else: # Linux
455-
subprocess.run(["xdg-open", config_path])
456-
457-
self.log_i18n(
458-
f"📝 Ouverture de {config_path}",
459-
f"📝 Opening {config_path}",
460-
)
461-
except Exception as e:
462-
QMessageBox.warning(
463-
self,
464-
self.tr("Attention", "Warning"),
465-
self.tr(
466-
f"Impossible d'ouvrir le fichier: {e}\nChemin: {config_path}",
467-
f"Failed to open file: {e}\nPath: {config_path}",
468-
),
469-
)
181+
"""Ouvre le fichier ARK_Main_Config.yml dans l'éditeur par défaut en déléguant à SetupWorkspace."""
182+
SetupWorkspace.open_ark_config(self)
470183

471184
def on_main_only_changed(self):
472185
if self.opt_main_only.isChecked():
@@ -543,25 +256,8 @@ def add_remove_file_button(self):
543256
pass
544257

545258
def remove_selected_file(self):
546-
selected_items = self.file_list.selectedItems()
547-
for item in selected_items:
548-
# Récupère le chemin relatif affiché
549-
rel_path = item.text()
550-
# Construit le chemin absolu si workspace_dir défini
551-
abs_path = (
552-
os.path.join(self.workspace_dir, rel_path)
553-
if self.workspace_dir
554-
else rel_path
555-
)
556-
# Supprime de python_files si présent
557-
if abs_path in self.python_files:
558-
self.python_files.remove(abs_path)
559-
# Supprime de selected_files si présent
560-
if abs_path in self.selected_files:
561-
self.selected_files.remove(abs_path)
562-
# Supprime l'item de la liste graphique
563-
self.file_list.takeItem(self.file_list.row(item))
564-
self.update_command_preview()
259+
"""Supprime les fichiers sélectionnés en déléguant à WorkspaceAdvancedManipulation."""
260+
WorkspaceAdvancedManipulation.remove_selected_file(self)
565261

566262
def show_help_dialog(self):
567263
# Minimal help dialog with current license information
@@ -1087,3 +783,4 @@ def closeEvent(self, event):
1087783
except Exception:
1088784
pass
1089785
event.accept()
786+

0 commit comments

Comments
 (0)