Skip to content

Commit

Permalink
Persist tab order on per-project basis between close/open.
Browse files Browse the repository at this point in the history
 - changed to collections which retain entry order
 - refresh storage on close if order changed

note:

opened files are stored per project, re-opening multiple projects will
restore the right order within the project but they will be sorted
by project as side effect.

opened projects might not have a deterministic order since they
come right from the lookup.
  • Loading branch information
mbien committed Jan 17, 2025
1 parent daa8132 commit 9d282c1
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1236,7 +1236,7 @@ static void shutdown() {
//a bit on magic here. We want to do the goup document persistence before notifyClosed in hope of the
// ant projects saving their project data before being closed. (ant ptojects call saveProjct() in the openclose hook.
// the caller of this method calls saveAllProjectt() later.
Group.onShutdown(new HashSet<Project>(INSTANCE.openProjects));
Group.onShutdown(new LinkedHashSet<>(INSTANCE.openProjects));
for (Project p : INSTANCE.openProjects) {
notifyClosed(p);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
import java.awt.event.ActionEvent;
import java.io.CharConversionException;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -112,21 +113,21 @@ public boolean open (FileObject fo) {
public Map<Project,Set<String>> close(final Project[] projects,
final boolean notifyUI) {
final Wrapper wr = new Wrapper();
wr.urls4project = new HashMap<Project,Set<String>>();
wr.urls4project = new LinkedHashMap<>();
doClose(projects, notifyUI, wr);
return wr.urls4project;
}

private void doClose(Project[] projects, boolean notifyUI, Wrapper wr) {
List<Project> listOfProjects = Arrays.asList(projects);
for (Project p : listOfProjects) { //#232668 all projects need an entry in the map - to handle projects without files correctly
wr.urls4project.put(p, new LinkedHashSet<String>());
wr.urls4project.put(p, new LinkedHashSet<>());
}
Set<DataObject> openFiles = new HashSet<DataObject>();
final Set<TopComponent> tc2close = new HashSet<TopComponent>();
Set<DataObject> openFiles = new LinkedHashSet<>();
List<TopComponent> tc2close = new ArrayList<>();

ERR.finer("Closing TCs");
final Set<TopComponent> openedTC = getOpenedTCs();
List<TopComponent> openedTC = getOpenedTCs();

for (TopComponent tc : openedTC) {
DataObject dobj = tc.getLookup().lookup(DataObject.class);
Expand Down Expand Up @@ -193,28 +194,25 @@ public void run() {
}
}

private Set<TopComponent> getOpenedTCs() {
final Set<TopComponent> openedTC = new HashSet<TopComponent>();
Runnable r = new Runnable() {
public void run() {
WindowManager wm = WindowManager.getDefault();
for (Mode mode : wm.getModes()) {
//#84546 - this condituon should allow us to close just editor related TCs that are in any imaginable mode.
if (!wm.isEditorMode(mode)) {
continue;
}
ERR.log(Level.FINER, "Closing TCs in mode {0}", mode.getName());
openedTC.addAll(Arrays.asList(wm.getOpenedTopComponents(mode)));
private List<TopComponent> getOpenedTCs() {
List<TopComponent> openedTC = new ArrayList<>();
Runnable onEDT = () -> {
WindowManager wm = WindowManager.getDefault();
for (Mode mode : wm.getModes()) {
//#84546 - this condituon should allow us to close just editor related TCs that are in any imaginable mode.
if (!wm.isEditorMode(mode)) {
continue;
}
ERR.log(Level.FINER, "Closing TCs in mode {0}", mode.getName());
openedTC.addAll(Arrays.asList(wm.getOpenedTopComponents(mode)));
}
};
if (SwingUtilities.isEventDispatchThread()) {
r.run();
onEDT.run();
} else {
try {
SwingUtilities.invokeAndWait(r);
}
catch (Exception ex) {
SwingUtilities.invokeAndWait(onEDT);
} catch (InterruptedException | InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
}
}
Expand Down Expand Up @@ -483,31 +481,31 @@ public static boolean closeAllDocuments(Project[] projects, boolean notifyUI, St
// store project's documents
// loop all project being closed
for (Map.Entry<Project,Set<String>> entry : urls4project.entrySet()) {
storeProjectOpenFiles(entry.getKey(), entry.getValue(), groupName);
storeProjectOpenFiles(entry.getKey(), new ArrayList<>(entry.getValue()), groupName);
}
}

return urls4project != null;
}

public static void storeProjectOpenFiles(Project p, Set<String> urls, String groupName) {
public static void storeProjectOpenFiles(Project p, List<String> urls, String groupName) {
AuxiliaryConfiguration aux = ProjectUtils.getAuxiliaryConfiguration(p);

Set<String> openFileUrls = getOpenFilesUrls(p, groupName);
if(urls.isEmpty() && openFileUrls.isEmpty()) {
List<String> openFileUrls = getOpenFilesUrls(p, groupName);
if (urls.isEmpty() && openFileUrls.isEmpty()) {
// was empty, stays empty, leave
return;
}
if(urls.size() == openFileUrls.size()) {
}
// check if file list changed, order matters
if (urls.size() == openFileUrls.size()) {
boolean same = true;
for (String url : openFileUrls) {
if(!urls.contains(url)) {
for (int i = 0; i < openFileUrls.size(); i++) {
if (!urls.get(i).equals(openFileUrls.get(i))) {
same = false;
break;
}
}
if(same) {
// nothing changed, leave
if (same) {
return;
}
}
Expand Down Expand Up @@ -558,8 +556,8 @@ public static Set<FileObject> openProjectFiles (Project p, Group grp) {
String groupName = grp == null ? null : grp.getName();
ERR.log(Level.FINE, "Trying to open files from {0}...", p);

Set<String> urls = getOpenFilesUrls(p, groupName);
Set<FileObject> toRet = new HashSet<FileObject>();
List<String> urls = getOpenFilesUrls(p, groupName);
Set<FileObject> toRet = new LinkedHashSet<>();
for (String url : urls) {
ERR.log(Level.FINE, "Will try to open {0}", url);
FileObject fo;
Expand Down Expand Up @@ -598,12 +596,12 @@ public static Set<FileObject> openProjectFiles (Project p, Group grp) {
return toRet;
}

private static Set<String> getOpenFilesUrls(Project p, String groupName) {
private static List<String> getOpenFilesUrls(Project p, String groupName) {
AuxiliaryConfiguration aux = ProjectUtils.getAuxiliaryConfiguration(p);

Element openFiles = aux.getConfigurationFragment (OPEN_FILES_ELEMENT, OPEN_FILES_NS2, false);
if (openFiles == null) {
return Collections.emptySet();
return Collections.emptyList();
}

Element groupEl = null;
Expand All @@ -619,11 +617,11 @@ private static Set<String> getOpenFilesUrls(Project p, String groupName) {
}

if (groupEl == null) {
return Collections.emptySet();
return Collections.emptyList();
}

NodeList list = groupEl.getElementsByTagNameNS(OPEN_FILES_NS2, FILE_ELEMENT);
Set<String> toRet = new HashSet<String>();
List<String> toRet = new ArrayList<>();
for (int i = 0; i < list.getLength (); i++) {
String url = list.item (i).getChildNodes ().item (0).getNodeValue ();
toRet.add(url);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -326,7 +326,7 @@ protected static String sanitizeNameAndUniquifyForId(String name) {
public static void onShutdown(Set<Project> prjs) {
Group active = getActiveGroup();
String oldGroupName = active != null ? active.getName() : null;
Set<Project> stayOpened = new HashSet<Project>(prjs);
Set<Project> stayOpened = new LinkedHashSet<>(prjs);
Map<Project, Set<DataObject>> documents = getOpenedDocuments(stayOpened, true);
for (Project p : stayOpened) {
Set<DataObject> oldDocuments = documents.get(p);
Expand All @@ -335,18 +335,18 @@ public static void onShutdown(Set<Project> prjs) {
}

private static void persistDocumentsInGroup(Project p, Set<DataObject> get, String oldGroupName) {
Set<String> urls = new HashSet<String>();
Set<String> urls = new LinkedHashSet<>();
if (get != null) {
for (DataObject dob : get) {
//same way of creating string as in ProjectUtilities
urls.add(dob.getPrimaryFile().toURL().toExternalForm());
}
}
ProjectUtilities.storeProjectOpenFiles(p, urls, oldGroupName);
ProjectUtilities.storeProjectOpenFiles(p, new ArrayList<>(urls), oldGroupName);
}

private static Map<Project, Set<DataObject>> getOpenedDocuments(final Set<Project> listOfProjects, boolean shutdown) {
final Map<Project, Set<DataObject>> toRet = new HashMap<Project, Set<DataObject>>();
Map<Project, Set<DataObject>> toRet = new LinkedHashMap<>();
Runnable runnable = new Runnable() {
@Override
public void run() {
Expand All @@ -364,11 +364,8 @@ public void run() {
Project owner = FileOwnerQuery.getOwner(fobj);

if (listOfProjects.contains(owner)) {
if (!toRet.containsKey(owner)) {
// add project
toRet.put(owner, new LinkedHashSet<DataObject>());
}
toRet.get(owner).add(dobj);
toRet.computeIfAbsent(owner, k -> new LinkedHashSet<>())
.add(dobj); // add project
}
}
}
Expand All @@ -379,9 +376,7 @@ public void run() {
assert !SwingUtilities.isEventDispatchThread();
try {
SwingUtilities.invokeAndWait(runnable);
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
} catch (InvocationTargetException ex) {
} catch (InterruptedException | InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
}
} else {
Expand Down

0 comments on commit 9d282c1

Please sign in to comment.