@@ -110,7 +110,7 @@ public abstract class AbstractBigViewer {
110110 protected final Map <String , Tree > renderedTrees = new LinkedHashMap <>();
111111
112112 /** Guards all access to {@link #renderedTrees} (and {@link #syncedPathManagerLabels}) */
113- private final Object renderedTreesLock = new Object ();
113+ final Object renderedTreesLock = new Object ();
114114
115115 /**
116116 * Labels of the trees rendered by the last {@link #syncPathManagerList()} call. Needed because
@@ -168,31 +168,33 @@ public boolean syncPathManagerList() {
168168 if (snt == null )
169169 throw new IllegalArgumentException ("Only available in SNT-tethered instances" );
170170 final java .util .Collection <Tree > trees = snt .getPathAndFillManager ().getTrees ();
171- if (trees .isEmpty ()) {
172- clearAllTrees ();
173- return false ;
174- }
175-
176- final java .util .Set <String > currentLabels = trees .stream ().map (Tree ::getLabel )
177- .collect (java .util .stream .Collectors .toSet ());
178- // See renderedTreesLock: this method can run concurrently with another instance of
179- // itself (or addTree()/removeTree()/clearAllTrees()/getRenderedTrees()) on a different
180- // background thread - guard every touch of renderedTrees/syncedPathManagerLabels
171+ // getTrees() builds each Tree from a label HashMap (PathAndFillManager#getTrees()), so within a single call
172+ // every Tree has a distinct, stable label - unlike renderedTrees' own keys, which are
173+ // getUniqueLabel()-disambiguated and can carry a "(n)" suffix from a genuinely-ambiguous historical add
174+ // (e.g. two files loaded with the same name). Removing and re-adding every tree on every sync routes new/kept
175+ // trees back through getUniqueLabel() and mints a brand new suffixed key even for an already-tracked tree
176+ // Here we match by bare label and update matching entries IN PLACE (same key, fresh Tree reference) so
177+ // unchanged trees are never removed from renderedTrees at all, are never touched by getUniqueLabel(), and
178+ // keep their cached screen geometry; only genuinely new trees go through addTree(), and only genuinely deleted
179+ // ones are removed
180+ final java .util .Map <String , Tree > newByLabel = new java .util .LinkedHashMap <>();
181+ for (final Tree t : trees ) newByLabel .put (t .getLabel (), t );
181182 synchronized (renderedTreesLock ) {
182- // A tree that has been entirely deleted from the Path Manager no longer appears in getTrees() at all,
183- // so it would never be matched by the "refresh existing labels" step. Prune it here by diffing against
184- // what was last rendered
185- final java . util . Set < String > stale = new java . util . HashSet <>( syncedPathManagerLabels );
186- stale . removeAll ( currentLabels );
187- stale . forEach ( renderedTrees . keySet ():: remove );
188- // Force a refresh of the trees that do still exist, so edits (nodes, color, selection) are picked up
189- // rather than just additions/removals
190- currentLabels . forEach ( renderedTrees . keySet ():: remove );
183+ final java . util . Iterator < java . util . Map . Entry < String , Tree >> it = renderedTrees . entrySet (). iterator ();
184+ while ( it . hasNext ()) {
185+ final java . util . Map . Entry < String , Tree > entry = it . next ();
186+ final Tree replacement = newByLabel . remove ( entry . getValue (). getLabel () );
187+ if ( replacement != null ) entry . setValue ( replacement ); // same key: reuse, don't re-add
188+ else it . remove (); // no longer in the Path Manager
189+ }
190+ // Whatever remains in newByLabel was never rendered before: genuinely new trees
191+ newByLabel . values (). forEach ( t -> addTree ( t , false )); // reentrant lock, safe to call here
191192 syncedPathManagerLabels .clear ();
192- syncedPathManagerLabels .addAll (currentLabels );
193+ syncedPathManagerLabels .addAll (trees .stream ().map (Tree ::getLabel )
194+ .collect (java .util .stream .Collectors .toSet ()));
193195 }
194- addCollection ( trees , true );
195- return true ;
196+ syncOverlays ( );
197+ return ! trees . isEmpty () ;
196198 }
197199
198200 /**
0 commit comments