Skip to content

Commit

Permalink
Modify the 'Close Active Editors' (plural) handler to add support for…
Browse files Browse the repository at this point in the history
… parts which represent an Editor and are contributed via eg. PartDescriptors in a Model Fragment. Associated with Issue#2176.

Include JUnit test.
  • Loading branch information
feilimb committed Oct 10, 2024
1 parent 83bf670 commit 0174c8f
Show file tree
Hide file tree
Showing 4 changed files with 372 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,32 @@

package org.eclipse.ui.internal;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionInfo;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.IWorkbench;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;

/**
* Closes all active editors
Expand All @@ -48,6 +62,25 @@ public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchPage page = window.getActivePage();
if (page != null) {
page.closeAllEditors(true);

// close parts representing editors which were contributed via
// eg. model fragment(s)
Collection<MPart> partsTaggedAsEditor = getContributedPartsTaggedAsEditor();
if (!partsTaggedAsEditor.isEmpty()) {
MApplication application = getApplicationModel();
EPartService partService = application.getContext().get(EPartService.class);
if (partService != null) {
for (MPart part : partsTaggedAsEditor) {
if (partService.savePart(part, true)) {
partService.hidePart(part);
}
}
// ensure the EnabledWhenExpression evaluation is performed
// otherwise the 'Close All Editors' will still appear enabled until
// the user clicks/selects a different part
getEvaluationService().requestEvaluation(ISources.ACTIVE_PART_NAME);
}
}
}

return null;
Expand All @@ -69,6 +102,12 @@ public EvaluationResult evaluate(IEvaluationContext context) {
if (refArray != null && refArray.length > 0) {
return EvaluationResult.TRUE;
}

// determine if we have any part contributions via model fragment
// which were tagged as being an 'Editor' (and which are to be rendered)
if (!getContributedPartsTaggedAsEditor().isEmpty()) {
return EvaluationResult.TRUE;
}
}
}
return EvaluationResult.FALSE;
Expand All @@ -83,4 +122,35 @@ public void collectExpressionInfo(ExpressionInfo info) {
}
return enabledWhen;
}

/**
* Collects part contributions from the application model which are not
* associated with compatibility layer editors, and are instead parts
* contributed via eg. model fragment, and which were tagged as representing an
* Editor, via the {@link Workbench#EDITOR_TAG} tag.
*
* @return a collection of (closable) part contributions from the application
* model, tagged as 'Editor' and not containing the parts associated
* with compatibility layer editors. Returns an empty collection if none
* are found
*/
private Collection<MPart> getContributedPartsTaggedAsEditor() {
MApplication application = getApplicationModel();
EModelService modelService = application.getContext().get(EModelService.class);

List<MPart> partsTaggedAsEditor = modelService != null
? modelService.findElements(application, null, MPart.class, Arrays.asList(Workbench.EDITOR_TAG))
: Collections.emptyList();

// remove parts which we wish to ignore: compatibility layer editors,
// non-closable parts, non-rendered parts
return partsTaggedAsEditor.stream().filter(p -> !CompatibilityEditor.MODEL_ELEMENT_ID.equals(p.getElementId())
&& p.isCloseable() && p.isToBeRendered()).collect(Collectors.toSet());
}

private MApplication getApplicationModel() {
BundleContext bundleContext = FrameworkUtil.getBundle(IWorkbench.class).getBundleContext();
ServiceReference<IWorkbench> reference = bundleContext.getServiceReference(IWorkbench.class);
return bundleContext.getService(reference).getApplication();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.eclipse.ui.tests.api.workbenchpart.OverriddenTitleTest;
import org.eclipse.ui.tests.api.workbenchpart.RawIViewPartTest;
import org.eclipse.ui.tests.api.workbenchpart.ViewPartTitleTest;
import org.eclipse.ui.tests.e4.CloseAllHandlerTest;
import org.eclipse.ui.tests.ide.api.FileEditorInputTest;
import org.eclipse.ui.tests.ide.api.IDETest;
import org.eclipse.ui.tests.ide.api.IDETest2;
Expand Down Expand Up @@ -83,7 +84,8 @@
SaveablesListTest.class,
PerspectiveExtensionReaderTest.class,
ModeledPageLayoutTest.class,
WorkbenchPluginTest.class
WorkbenchPluginTest.class,
CloseAllHandlerTest.class
})
public class ApiTestSuite {

Expand Down
Loading

0 comments on commit 0174c8f

Please sign in to comment.