Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persist tab order on per-project basis between close/open. #8164

Merged
merged 1 commit into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,35 +481,22 @@ 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) {
AuxiliaryConfiguration aux = ProjectUtils.getAuxiliaryConfiguration(p);

Set<String> openFileUrls = getOpenFilesUrls(p, groupName);
if(urls.isEmpty() && openFileUrls.isEmpty()) {
// was empty, stays empty, leave
return;
}
if(urls.size() == openFileUrls.size()) {
boolean same = true;
for (String url : openFileUrls) {
if(!urls.contains(url)) {
same = false;
break;
}
}
if(same) {
// nothing changed, leave
return;
}
public static void storeProjectOpenFiles(Project p, List<String> urls, String groupName) {

List<String> openFileUrls = getOpenFilesUrls(p, groupName);
// check if file list changed, order matters
if (urls.equals(openFileUrls)) {
return;
}


AuxiliaryConfiguration aux = ProjectUtils.getAuxiliaryConfiguration(p);
aux.removeConfigurationFragment (OPEN_FILES_ELEMENT, OPEN_FILES_NS, false);

Element openFiles = aux.getConfigurationFragment(OPEN_FILES_ELEMENT, OPEN_FILES_NS2, false);
Expand Down Expand Up @@ -558,8 +543,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 +583,13 @@ public static Set<FileObject> openProjectFiles (Project p, Group grp) {
return toRet;
}

private static Set<String> getOpenFilesUrls(Project p, String groupName) {
/// Returns an deduplicated list of opened file URLs in encounter order for this project and group.
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,16 +605,16 @@ 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>();
Set<String> set = new LinkedHashSet<>();
for (int i = 0; i < list.getLength (); i++) {
String url = list.item (i).getChildNodes ().item (0).getNodeValue ();
toRet.add(url);
String url = list.item(i).getChildNodes().item(0).getNodeValue();
set.add(url);
}
return toRet;
return new ArrayList<>(set);
}

// interface for handling project's documents stored in project private.xml
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
Loading