Problem
Die TreeTableComponent in TL8 scheint ihre Selektion nicht zu verlieren, wenn sie ein neues Model erhält, das zu einer leeren Kindliste führt, oder wenn als Default-Selektion explizit "null" konfiguriert wird.
Ich habe einen Projektebaum (TreeTableComponent). Dieser erhält sein Modell (Rootknoten einer Struktur) von einer Kachelkomponente. Der Baum zeigt die Substruktur des Models an (children rekursiv). Daneben gibt es weitere Tabs, die als Model die Selektion des Baumes erhalten.
Die Komponentenhierarchie ist:
tileLayout (InlinedTileComponent, name="Objects")
└─ projectStructuresInnerLayout (layout.template)
├─ projectTreeTable (TreeTable, name="TreeTable")
│ model = selection(tileLayout#Objects) ← Kachel-Selektion
└─ tabbar
├─ profile/profileForm
│ model = selection(projectTreeTable#TreeTable) ← Baum-Selektion
└─ ... (weitere Tabs)
Wechselt man nun in eine andere Kachel, in der es aber keine Kindobjekte gibt, also der Baum leer bleibt, behalten die weiteren Tabs das alte Model der alten Kachel, anstatt sich wegen "Kein Objekt selektiert" auszublenden, wie es in TL 7 der Fall war. Betrachtet man sich dabei den Baum, hat dieser immer noch das alte Projekt der alten Struktur als Selektion. Das ist falsch.
In diesem Zuge fällt auch auf, dass wenn man ein Objekt selektiert hat, und dieses dann aufgrund des Tabellenfilters verschwindet, und der baum dadurch nichts mehr selektiert hat, die Selektion des Baums trotzdem weiterhin erhalten bleibt und die Tabs weiterhin das alte Modell anzeigen. Dies war in TL7 jedoch auch schon so der Fall.
Analyse
Regression aus #29402: Beim Neuaufbau des Baums (invalidate() nach einem Modellwechsel) wird das Selektionsmodell geleert, ohne den Selektionskanal zu ändern, damit die Selektion bei einem Neuaufbau für dasselbe Modell wiederhergestellt werden kann. validateSelection() findet den alten Selektionspfad im neuen Baum nicht und setzt die Default-Selektion. Ist diese leer (leerer Baum oder default-selection="false"), ändert sich das bereits leere Selektionsmodell nicht, es wird kein Selektions-Event ausgelöst, und der Selektionskanal behält den Pfad zum alten Objekt. Abhängige Komponenten zeigen dadurch weiter das alte Objekt an.
Tabellenfilter: Ein Filter ändert nur die Ansicht. Eine durch den Filter ausgeblendete Selektion bleibt in der klassischen TableComponent/`TreeTableComponent` erhalten (wie in TL7). In der React-Tabelle (TableViewControl) blieb sie zunächst ebenfalls erhalten, wurde aber beim nächsten, davon unabhängigen Neuladen der Zeilen (refreshData()) verworfen und der Selektionskanal auf null gesetzt, weil dort gegen die gefilterten (bzw. in eingeklappten Gruppen verborgenen) Zeilen abgeglichen wurde statt gegen alle Zeilen. Ebenso verwarf ein Wechsel der Gruppierung ausgeblendete selektierte Zeilen stillschweigend, und ein Kanalwert für eine ausgeblendete Zeile wurde nicht als Selektion übernommen.
Lösung
- TreeTableComponent.validateSelection() schreibt die Selektion, die sie schließlich herstellt, in den Selektionskanal zurück. Eine noch auflösbare bzw. noch gültige Selektion bleibt dabei unverändert erhalten (auch bei default-selection="false"); nur ein Pfad, der im neuen Baum nicht mehr existiert, ohne dass eine Ersatzselektion gefunden wird, führt zu einer leeren Selektion im Kanal. Abhängige Komponenten sehen dann wie in TL7 "Kein Objekt selektiert".
- React-Tabelle: Die Selektion richtet sich nach den Daten der Tabelle, nicht nach dem sichtbaren Ausschnitt. Neue Methode containedKeys(...) an RowSource/`TableView` liefert die Schlüssel, für die die Daten eine Zeile enthalten, unabhängig von Filter und eingeklappten Gruppen/Knoten. ** TableViewControl.refreshData() gleicht die Selektion gegen alle Zeilen ab; eine durch Filter oder eingeklappte Gruppe ausgeblendete Zeile bleibt selektiert, solange ihr Objekt in den Daten enthalten ist. ** Ein Wechsel der Gruppierung verwirft keine ausgeblendeten selektierten Zeilen mehr. ** selectRows(...) (Kanalwert -> Tabelle) übernimmt auch eine in den Daten enthaltene, aber ausgeblendete Zeile als Selektion; sie wird angezeigt, sobald der Filter aufgehoben ist, und zurückgesetzt, sobald das Objekt aus den Daten verschwindet. Ein Wert ohne Zeile in den Daten wird wie bisher behandelt.
- Das Zurücksetzen der Selektion bei Eingabewechsel funktioniert im React-Baum (TreeSelectionBinding) bereits korrekt und bleibt unverändert.
- Demo: Die Baumtabelle "Baumtabelle mit Mehrfachauswahl" (Technisches Demo > Komponenten > Tabellen und Bäume) hat einen Button "Aktualisieren"; Test TestResetTreeTableSelectionOnModelChange.