Skip to content

Commit

Permalink
TreeSelectionSynchroniser - check that open editor parts are not zombies
Browse files Browse the repository at this point in the history
- Check that all diagram editor parts have a diagram model
- This can happen if an editor part is open and its model file is missing. We don't want to select objects on these parts
- Also check diagram model is not null in AbstractDiagramEditor and ArchimateDiagramEditor
- Also remove deprecated selectArchimateConcepts method
- Refactor so that TreeSelectionSynchroniser is a preference listener
  • Loading branch information
Phillipus committed Jan 15, 2025
1 parent 0781da2 commit 4a901d4
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ public void deactivateContext() {
@Override
public void selectObjects(Object[] objects) {
// Safety check in case this is called via Display#asyncExec()
if(getGraphicalViewer() == null || getGraphicalViewer().getControl() == null) {
if(getGraphicalViewer() == null || getGraphicalViewer().getControl() == null || getModel() == null) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,13 @@ protected void registerContextMenu(GraphicalViewer viewer) {
getSite().registerContextMenu(ArchimateDiagramEditorContextMenuProvider.ID, provider, viewer);
}

@Override
@Deprecated
public void selectArchimateConcepts(IArchimateConcept[] archimateConcepts) {
selectObjects(archimateConcepts);
}

@Override
public void selectObjects(Object[] objects) {
// Safety check in case this is a zombie editor part
if(getModel() == null) {
return;
}

Set<Object> selection = new HashSet<>();

for(Object object : objects) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
*/
package com.archimatetool.editor.diagram;

import com.archimatetool.model.IArchimateConcept;


/**
* IDiagramEditor
*
Expand All @@ -17,12 +14,4 @@ public interface IArchimateDiagramEditor extends IDiagramModelEditor {
String ID = "com.archimatetool.editor.diagramEditor"; //$NON-NLS-1$
String HELP_ID = "com.archimatetool.help.diagramEditorHelp"; //$NON-NLS-1$
String PALETTE_HELP_ID = "com.archimatetool.help.diagramEditorPaletteHelp"; //$NON-NLS-1$

/**
* Select the graphical objects wrapping the Archimate concepts
* Deprecated use selectObjects(Object[] objects)
* @param archimateConcepts
*/
@Deprecated
void selectArchimateConcepts(IArchimateConcept[] archimateConcepts);
}
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ private void makeActions() {

fActionProperties = new PropertiesAction(getSelectionProvider());

fActionLinkToEditor = new LinkToEditorAction(fSynchroniser);
fActionLinkToEditor = new LinkToEditorAction();

fActionDuplicate = new DuplicateAction(getViewer());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@

import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
Expand Down Expand Up @@ -54,15 +53,15 @@ public class TreeSelectionSynchroniser implements ISelectionChangedListener {
private PartListenerAdapter partListenerAdapter = new PartListenerAdapter() {
@Override
public void partOpened(IWorkbenchPart part) {
if(part instanceof IDiagramModelEditor) {
registerEditor((IDiagramModelEditor)part);
if(part instanceof IDiagramModelEditor editor) {
registerEditor(editor);
}
}

@Override
public void partClosed(IWorkbenchPart part) {
if(part instanceof IDiagramModelEditor) {
unregisterEditor((IDiagramModelEditor)part);
if(part instanceof IDiagramModelEditor editor) {
unregisterEditor(editor);
}

// This is important for garbage collection!
Expand All @@ -79,10 +78,8 @@ public void partActivated(IWorkbenchPart part) {
}

// Select all types of diagram in Tree
if(part instanceof IDiagramModelEditor) {
IDiagramModelEditor editor = (IDiagramModelEditor)part;

// Editor model could be null if model's file was deleted/renamed and app opened
if(part instanceof IDiagramModelEditor editor) {
// Editor model could be null if model's file was deleted/renamed and app opened (zombie editor part)
if(editor.getModel() != null && doSync()) {
fTreeViewer.setSelection(new StructuredSelection(editor.getModel()), true);
}
Expand All @@ -91,19 +88,26 @@ public void partActivated(IWorkbenchPart part) {
}
}
};

private IPropertyChangeListener prefsListener = event -> {
if(event.getProperty().equals(IPreferenceConstants.LINK_VIEW) && event.getNewValue() == Boolean.TRUE) {
updateSelection();
}
};

TreeSelectionSynchroniser(TreeModelViewer treeViewer) {
fTreeViewer = treeViewer;
registerListeners();

treeViewer.getTree().addDisposeListener((e) -> {
treeViewer.getTree().addDisposeListener(e -> {
unregisterListeners();

// Ensure this stuff can be garbage collected
fTreeViewer = null;
lastActiveEditor = null;
lastSelectionEvent = null;
partListenerAdapter = null;
prefsListener = null;
});
}

Expand All @@ -122,14 +126,12 @@ private boolean doSync() {
/**
* Update with the last known selection
*/
public void updateSelection() {
private void updateSelection() {
// In this case we have created a new TreeViewer and synchroniser, so create a new selection event
if(lastSelectionEvent == null) {
IEditorPart activeEditor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
if(activeEditor instanceof IDiagramModelEditor) {
GraphicalViewer source = ((IDiagramModelEditor)activeEditor).getGraphicalViewer();
ISelection selection = source.getSelection();
selectionChanged(new SelectionChangedEvent(source, selection));
if(activeEditor instanceof IDiagramModelEditor editor && editor.getGraphicalViewer() instanceof GraphicalViewer viewer) { // check this is not a zombie editor part
selectionChanged(new SelectionChangedEvent(viewer, viewer.getSelection()));
}
}
else {
Expand All @@ -152,24 +154,23 @@ public void selectionChanged(SelectionChangedEvent event) {

isSelecting = true;

ISelection selection = event.getSelection();
Object source = event.getSource();
Object[] selectedObjects = event.getStructuredSelection().toArray();

// Selection from a Diagram Editor, so select objects in the Tree
if(source instanceof GraphicalViewer) {
List<Object> selected = new ArrayList<Object>();
List<Object> selected = new ArrayList<>();

for(Object o : ((IStructuredSelection)selection).toArray()) {
if(o instanceof EditPart) {
Object model = ((EditPart)o).getModel();
for(Object o : selectedObjects) {
if(o instanceof EditPart editPart) {
Object model = editPart.getModel();
// Archimate concept
if(model instanceof IDiagramModelArchimateComponent) {
model = ((IDiagramModelArchimateComponent)model).getArchimateConcept();
selected.add(model);
if(model instanceof IDiagramModelArchimateComponent dmc) {
selected.add(dmc.getArchimateConcept());
}
// Diagram model reference
else if (model instanceof IDiagramModelReference) {
selected.add(((IDiagramModelReference)model).getReferencedModel());
else if (model instanceof IDiagramModelReference dmr) {
selected.add(dmr.getReferencedModel());
}
// Diagram model
else if(model instanceof IDiagramModel) {
Expand All @@ -185,7 +186,7 @@ else if(model instanceof IDiagramModel) {
else if(source instanceof TreeViewer) {
// Select these (or an empty selection) in the Diagram Editors
for(IDiagramModelEditor editor : getOpenEditors()) {
editor.selectObjects(((IStructuredSelection)selection).toArray());
editor.selectObjects(selectedObjects);
}
}

Expand All @@ -204,6 +205,9 @@ private void registerListeners() {
for(IDiagramModelEditor editor : getOpenEditors()) {
registerEditor(editor);
}

// Preference listener
ArchiPlugin.PREFERENCES.addPropertyChangeListener(prefsListener);
}

private void unregisterListeners() {
Expand All @@ -218,17 +222,20 @@ private void unregisterListeners() {
for(IDiagramModelEditor editor : getOpenEditors()) {
unregisterEditor(editor);
}

// Preference listener
ArchiPlugin.PREFERENCES.removePropertyChangeListener(prefsListener);
}

private void registerEditor(IDiagramModelEditor editor) {
GraphicalViewer viewer = editor.getAdapter(GraphicalViewer.class);
GraphicalViewer viewer = editor.getGraphicalViewer();
if(viewer != null) {
viewer.addSelectionChangedListener(this);
}
}

private void unregisterEditor(IDiagramModelEditor editor) {
GraphicalViewer viewer = editor.getAdapter(GraphicalViewer.class);
GraphicalViewer viewer = editor.getGraphicalViewer();
if(viewer != null) {
viewer.removeSelectionChangedListener(this);
}
Expand All @@ -239,9 +246,9 @@ private List<IDiagramModelEditor> getOpenEditors() {

IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
for(IEditorReference ref : page.getEditorReferences()) {
IEditorPart part = ref.getEditor(false);
if(part instanceof IDiagramModelEditor) {
list.add((IDiagramModelEditor)part);
// Editor model could be null if model's file was deleted/renamed and app opened (zombie editor part)
if(ref.getEditor(false) instanceof IDiagramModelEditor editor && editor.getModel() != null) {
list.add(editor);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import com.archimatetool.editor.ArchiPlugin;
import com.archimatetool.editor.preferences.IPreferenceConstants;
import com.archimatetool.editor.ui.IArchiImages;
import com.archimatetool.editor.views.tree.TreeSelectionSynchroniser;



Expand All @@ -22,21 +21,14 @@
*/
public class LinkToEditorAction extends Action {

private TreeSelectionSynchroniser syncer;

public LinkToEditorAction(TreeSelectionSynchroniser syncer) {
public LinkToEditorAction() {
super(Messages.LinkToEditorAction_0, IAction.AS_CHECK_BOX);
setImageDescriptor(IArchiImages.ImageFactory.getImageDescriptor(IArchiImages.ICON_LINKED));
setChecked(ArchiPlugin.PREFERENCES.getBoolean(IPreferenceConstants.LINK_VIEW));
this.syncer = syncer;
}

@Override
public void run() {
ArchiPlugin.PREFERENCES.setValue(IPreferenceConstants.LINK_VIEW, isChecked());
if(isChecked()) {
syncer.updateSelection();
}
}

}

0 comments on commit 4a901d4

Please sign in to comment.