Skip to content

Commit ca41ae8

Browse files
committed
Fix: Make object properties tab selection more predictable
Fixes #271
1 parent 4da207a commit ca41ae8

4 files changed

Lines changed: 112 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ See DataLab [roadmap page](https://datalab-platform.com/en/contributing/roadmap.
5353
* ROI bounding boxes are now properly clipped to image boundaries, and fully out-of-bounds ROIs return NaN statistics values
5454
* This fix is implemented in Sigima library (see [Issue #1](https://github.com/DataLab-Platform/Sigima/issues/1) - `ValueError` when computing statistics on ROI extending beyond image boundaries)
5555

56+
**Object property panel tab selection:**
57+
58+
* Fixed tab selection behavior in object properties panel to be more predictable and user-friendly
59+
* Properties tab is now always shown by default when switching between objects, providing consistent navigation
60+
* Creation, Processing, and Analysis tabs now appear automatically only once after their respective triggering events (object creation, 1-to-1 processing, or analysis computation), then revert to Properties tab for subsequent selections
61+
* This eliminates the confusing behavior where the tab would arbitrarily persist or change based on previous selections
62+
* This closes [Issue #271](https://github.com/datalab-platform/datalab/issues/271) - Improve object property panel tab selection behavior
63+
5664
## DataLab Version 1.0.1 ##
5765

5866
This major release represents a significant milestone for DataLab with numerous enhancements across all areas. The changes are organized by category for easier navigation.

datalab/gui/panel/base.py

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ def __init__(self, panel: BaseDataPanel, objclass: SignalObj | ImageObj) -> None
216216
self.analysis_parameters.setReadOnly(True)
217217
self.analysis_parameters.setFont(font)
218218

219+
# Track newly created objects to show Creation tab only once
220+
self._newly_created_obj_uuid: str | None = None
221+
# Track when analysis results were just computed
222+
self._fresh_analysis_obj_uuid: str | None = None
223+
# Track when object was just processed (1-to-1)
224+
self._fresh_processing_obj_uuid: str | None = None
225+
219226
self.tabwidget.addTab(
220227
self.processing_history, get_icon("history.svg"), _("History")
221228
)
@@ -370,11 +377,16 @@ def __update_properties_dataset(self, obj: SignalObj | ImageObj) -> None:
370377
self.properties.get()
371378
self.properties.apply_button.setEnabled(False)
372379

373-
def update_properties_from(self, obj: SignalObj | ImageObj | None = None) -> None:
380+
def update_properties_from(
381+
self,
382+
obj: SignalObj | ImageObj | None = None,
383+
force_tab: Literal["creation", "processing", "analysis", None] | None = None,
384+
) -> None:
374385
"""Update properties panel (properties, creation, processing) from object.
375386
376387
Args:
377388
obj: Signal or Image object
389+
force_tab: Force a specific tab to be current
378390
"""
379391
self.properties.setDisabled(obj is None)
380392
if obj is None:
@@ -411,30 +423,56 @@ def update_properties_from(self, obj: SignalObj | ImageObj | None = None) -> Non
411423
self.processing_scroll = None
412424

413425
# Setup Creation and Processing tabs (if applicable)
414-
has_creation_tab = has_processing_tab = False
426+
has_creation_tab = False
427+
has_processing_tab = False
415428
if obj is not None:
416429
has_creation_tab = self.setup_creation_tab(obj)
417-
has_processing_tab = self.setup_processing_tab(obj)
430+
has_processing_tab = self.setup_processing_tab(obj) # Processing tab setup
418431

419432
# Trigger visibility update for History and Analysis parameters tabs
420433
# (will be called via textChanged signals, but we call explicitly
421434
# here to ensure initial state is correct)
422435
self._update_tab_visibility()
423436

424-
# Handle priority regarding the tab to set as current:
425-
# 1. Analysis parameters if content exists
426-
# 2. Creation tab if it exists
427-
# 3. Processing tab if it exists
428-
# 4. Properties tab
429-
if has_analysis_parameters:
430-
self.tabwidget.setCurrentWidget(self.analysis_parameters)
431-
elif has_creation_tab:
437+
# Determine which tab to show based on force_tab parameter:
438+
# - If force_tab="creation" and Creation tab exists, show it
439+
# - If force_tab="processing" and Processing tab exists, show it
440+
# - If force_tab="analysis" and Analysis tab has content, show it
441+
# - Otherwise, always show Properties tab (default behavior)
442+
if force_tab == "creation" and has_creation_tab:
432443
self.tabwidget.setCurrentWidget(self.creation_scroll)
433-
elif has_processing_tab:
444+
elif force_tab == "processing" and has_processing_tab:
434445
self.tabwidget.setCurrentWidget(self.processing_scroll)
446+
elif force_tab == "analysis" and has_analysis_parameters:
447+
self.tabwidget.setCurrentWidget(self.analysis_parameters)
435448
else:
449+
# Default: always show Properties tab when switching objects
436450
self.tabwidget.setCurrentWidget(self.properties)
437451

452+
def mark_as_newly_created(self, obj: SignalObj | ImageObj) -> None:
453+
"""Mark object to show Creation tab on next selection.
454+
455+
Args:
456+
obj: Object to mark
457+
"""
458+
self._newly_created_obj_uuid = get_uuid(obj)
459+
460+
def mark_as_freshly_processed(self, obj: SignalObj | ImageObj) -> None:
461+
"""Mark object to show Processing tab on next selection.
462+
463+
Args:
464+
obj: Object to mark
465+
"""
466+
self._fresh_processing_obj_uuid = get_uuid(obj)
467+
468+
def mark_as_fresh_analysis(self, obj: SignalObj | ImageObj) -> None:
469+
"""Mark object to show Analysis tab on next selection.
470+
471+
Args:
472+
obj: Object to mark
473+
"""
474+
self._fresh_analysis_obj_uuid = get_uuid(obj)
475+
438476
def get_changed_properties(self) -> dict[str, Any]:
439477
"""Get dictionary of properties that have changed from original values.
440478
@@ -1490,6 +1528,16 @@ def add_object(
14901528
obj.check_data()
14911529
self.objmodel.add_object(obj, group_id)
14921530

1531+
# Mark this object as newly created to show Creation tab on first selection
1532+
# BUT: Don't overwrite if this object is already marked as freshly processed
1533+
# or has fresh analysis results (those take precedence)
1534+
obj_uuid = get_uuid(obj)
1535+
if (
1536+
obj_uuid != self.objprop._fresh_processing_obj_uuid
1537+
and obj_uuid != self.objprop._fresh_analysis_obj_uuid
1538+
):
1539+
self.objprop.mark_as_newly_created(obj)
1540+
14931541
# Block signals to avoid updating the plot (unnecessary refresh)
14941542
self.objview.blockSignals(True)
14951543
self.objview.add_object_item(obj, group_id, set_current=set_current)
@@ -2419,7 +2467,26 @@ def selection_changed(self, update_items: bool = False) -> None:
24192467
"""
24202468
selected_objects = self.objview.get_sel_objects(include_groups=True)
24212469
selected_groups = self.objview.get_sel_groups()
2422-
self.objprop.update_properties_from(self.objview.get_current_object())
2470+
2471+
# Determine which tab to show based on object state
2472+
current_obj = self.objview.get_current_object()
2473+
force_tab = None
2474+
if current_obj is not None:
2475+
obj_uuid = get_uuid(current_obj)
2476+
# Show Creation tab for newly created objects (only once)
2477+
if obj_uuid == self.objprop._newly_created_obj_uuid:
2478+
force_tab = "creation"
2479+
self.objprop._newly_created_obj_uuid = None
2480+
# Show Processing tab for freshly processed objects (only once)
2481+
elif obj_uuid == self.objprop._fresh_processing_obj_uuid:
2482+
force_tab = "processing"
2483+
self.objprop._fresh_processing_obj_uuid = None
2484+
# Show Analysis tab for objects with fresh analysis results
2485+
elif obj_uuid == self.objprop._fresh_analysis_obj_uuid:
2486+
force_tab = "analysis"
2487+
self.objprop._fresh_analysis_obj_uuid = None
2488+
2489+
self.objprop.update_properties_from(current_obj, force_tab=force_tab)
24232490
self.acthandler.selected_objects_changed(selected_groups, selected_objects)
24242491
self.refresh_plot("selected", update_items, False)
24252492

datalab/gui/processor/base.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,9 @@ def _compute_1_to_1_subroutine(
11221122
)
11231123
insert_processing_parameters(new_obj, pp)
11241124

1125+
# Mark object as freshly processed to show Processing tab
1126+
self.panel.objprop.mark_as_freshly_processed(new_obj)
1127+
11251128
new_gid = None
11261129
if grps:
11271130
# If groups are selected, then it means that there is no
@@ -1417,6 +1420,8 @@ def compute_1_to_0(
14171420
rdata.append(adapter, obj)
14181421

14191422
if obj is current_obj:
1423+
# Mark object as having fresh analysis results to show Analysis tab
1424+
self.panel.objprop.mark_as_fresh_analysis(obj)
14201425
self.panel.selection_changed(update_items=True)
14211426
else:
14221427
self.panel.refresh_plot(get_uuid(obj), True, False)

doc/locale/fr/LC_MESSAGES/changelog.po

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ msgid ""
77
msgstr ""
88
"Project-Id-Version: DataLab \n"
99
"Report-Msgid-Bugs-To: \n"
10-
"POT-Creation-Date: 2025-11-30 12:33+0100\n"
10+
"POT-Creation-Date: 2025-11-30 15:30+0100\n"
1111
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1212
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313
"Language: fr\n"
@@ -123,6 +123,24 @@ msgstr "Les boîtes englobantes des ROI sont désormais correctement limitées a
123123
msgid "This fix is implemented in Sigima library (see [Issue #1](https://github.com/DataLab-Platform/Sigima/issues/1) - `ValueError` when computing statistics on ROI extending beyond image boundaries)"
124124
msgstr "Cette correction est implémentée dans la bibliothèque Sigima (voir [Issue #1](https://github.com/DataLab-Platform/Sigima/issues/1) - `ValueError` lors du calcul des statistiques sur ROI s'étendant au-delà des limites de l'image)"
125125

126+
msgid "**Object property panel tab selection:**"
127+
msgstr "**Sélection des onglets du panneau des propriétés des objets :**"
128+
129+
msgid "Fixed tab selection behavior in object properties panel to be more predictable and user-friendly"
130+
msgstr "Correction du comportement de sélection des onglets dans le panneau des propriétés des objets pour le rendre plus prévisible et convivial"
131+
132+
msgid "Properties tab is now always shown by default when switching between objects, providing consistent navigation"
133+
msgstr "L'onglet Propriétés est désormais toujours affiché par défaut lors du changement d'objet, offrant une navigation cohérente"
134+
135+
msgid "Creation, Processing, and Analysis tabs now appear automatically only once after their respective triggering events (object creation, 1-to-1 processing, or analysis computation), then revert to Properties tab for subsequent selections"
136+
msgstr "Les onglets Création, Traitement et Analyse apparaissent désormais automatiquement une seule fois après leurs événements déclencheurs respectifs (création d'objet, traitement 1-vers-1 ou calcul d'analyse), puis reviennent à l'onglet Propriétés pour les sélections ultérieures"
137+
138+
msgid "This eliminates the confusing behavior where the tab would arbitrarily persist or change based on previous selections"
139+
msgstr "Cela élimine le comportement déroutant où l'onglet persistait ou changeait arbitrairement en fonction des sélections précédentes"
140+
141+
msgid "This closes [Issue #271](https://github.com/datalab-platform/datalab/issues/271) - Improve object property panel tab selection behavior"
142+
msgstr "Ceci clôture [Issue #271](https://github.com/datalab-platform/datalab/issues/271) - Amélioration du comportement de sélection des onglets du panneau des propriétés des objets"
143+
126144
msgid "DataLab Version 1.0.1"
127145
msgstr "DataLab Version 1.0.1"
128146

0 commit comments

Comments
 (0)