1515 ********************************************************************************/
1616package org .eclipse .glsp .ide .editor .ui ;
1717
18+ import static java .util .stream .Collectors .toList ;
19+
1820import java .io .UnsupportedEncodingException ;
1921import java .net .URI ;
2022import java .net .URLEncoder ;
23+ import java .util .ArrayList ;
2124import java .util .HashMap ;
25+ import java .util .List ;
2226import java .util .Map ;
2327import java .util .Optional ;
28+ import java .util .Set ;
2429import java .util .UUID ;
2530import java .util .concurrent .CompletableFuture ;
2631import java .util .concurrent .atomic .AtomicInteger ;
2732import java .util .stream .Stream ;
2833
2934import org .apache .logging .log4j .LogManager ;
3035import org .apache .logging .log4j .Logger ;
36+ import org .eclipse .core .commands .common .EventManager ;
3137import org .eclipse .core .resources .IFile ;
3238import org .eclipse .core .resources .IMarker ;
3339import org .eclipse .core .runtime .IProgressMonitor ;
3440import org .eclipse .e4 .core .contexts .IEclipseContext ;
41+ import org .eclipse .glsp .graph .GModelElement ;
3542import org .eclipse .glsp .ide .editor .GLSPServerManager ;
3643import org .eclipse .glsp .ide .editor .actions .GLSPActionProvider ;
3744import org .eclipse .glsp .ide .editor .actions .InvokeCopyAction ;
3845import org .eclipse .glsp .ide .editor .actions .InvokeCutAction ;
3946import org .eclipse .glsp .ide .editor .actions .InvokeDeleteAction ;
4047import org .eclipse .glsp .ide .editor .actions .InvokePasteAction ;
48+ import org .eclipse .glsp .ide .editor .actions .handlers .IdeSelectActionHandler ;
4149import org .eclipse .glsp .ide .editor .di .IdeActionDispatcher ;
4250import org .eclipse .glsp .ide .editor .internal .utils .UrlUtils ;
4351import org .eclipse .glsp .ide .editor .utils .GLSPDiagramEditorMarkerUtil ;
4654import org .eclipse .glsp .server .actions .Action ;
4755import org .eclipse .glsp .server .actions .ActionDispatcher ;
4856import org .eclipse .glsp .server .actions .SaveModelAction ;
57+ import org .eclipse .glsp .server .actions .SelectAction ;
4958import org .eclipse .glsp .server .actions .SelectAllAction ;
5059import org .eclipse .glsp .server .actions .ServerStatusAction ;
5160import org .eclipse .glsp .server .disposable .DisposableCollection ;
6069import org .eclipse .jetty .server .ServerConnector ;
6170import org .eclipse .jface .action .IAction ;
6271import org .eclipse .jface .action .MenuManager ;
72+ import org .eclipse .jface .viewers .ISelection ;
73+ import org .eclipse .jface .viewers .ISelectionChangedListener ;
74+ import org .eclipse .jface .viewers .ISelectionProvider ;
75+ import org .eclipse .jface .viewers .SelectionChangedEvent ;
76+ import org .eclipse .jface .viewers .StructuredSelection ;
6377import org .eclipse .swt .SWT ;
6478import org .eclipse .swt .browser .Browser ;
6579import org .eclipse .swt .browser .ProgressListener ;
8195
8296import com .google .inject .Injector ;
8397
84- public class GLSPDiagramEditor extends EditorPart implements IGotoMarker {
98+ public class GLSPDiagramEditor extends EditorPart implements IGotoMarker , ISelectionProvider {
8599 /**
86100 * {@link IEclipseContext} key for the current client id. The associated value
87101 * is a {@link String}.
@@ -103,6 +117,9 @@ public class GLSPDiagramEditor extends EditorPart implements IGotoMarker {
103117 protected final CompletableFuture <Injector > injector = new CompletableFuture <>();
104118 protected boolean dirty ;
105119
120+ protected final SelectionManager selectionListener = new SelectionManager ();
121+ private StructuredSelection currentSelection = StructuredSelection .EMPTY ;
122+
106123 protected final DisposableCollection toDispose = new DisposableCollection ();
107124
108125 protected final Map <String , IAction > globalActions = new HashMap <>(Map .of (
@@ -308,10 +325,12 @@ public void createPartControl(final Composite parent) {
308325
309326 setPartName (generatePartName ());
310327
311- this . browser = createBrowser (root );
328+ browser = createBrowser (root );
312329 setupBrowser (this .browser );
313330
314- this .statusBar = createStatusBar (root );
331+ statusBar = createStatusBar (root );
332+
333+ getSite ().setSelectionProvider (this );
315334 }
316335
317336 protected String generatePartName () {
@@ -454,4 +473,110 @@ public void run() {
454473 }
455474 };
456475 }
476+
477+ protected static class SelectionManager extends EventManager {
478+
479+ public void addSelectionChangedListener (final ISelectionChangedListener listener ) {
480+ addListenerObject (listener );
481+ }
482+
483+ public void removeSelectionChangedListener (final ISelectionChangedListener listener ) {
484+ removeListenerObject (listener );
485+ }
486+
487+ public void selectionChanged (final SelectionChangedEvent event ) {
488+ for (Object listener : getListeners ()) {
489+ final ISelectionChangedListener selectionChangedListeners = (ISelectionChangedListener ) listener ;
490+ UIUtil .asyncExec (() -> selectionChangedListeners .selectionChanged (event ));
491+ }
492+ }
493+
494+ }
495+
496+ @ Override
497+ public void addSelectionChangedListener (final ISelectionChangedListener listener ) {
498+ selectionListener .addSelectionChangedListener (listener );
499+ }
500+
501+ @ Override
502+ public void removeSelectionChangedListener (final ISelectionChangedListener listener ) {
503+ selectionListener .removeSelectionChangedListener (listener );
504+ }
505+
506+ @ Override
507+ public ISelection getSelection () { return currentSelection ; }
508+
509+ /**
510+ * Sets the selection on the client by dispatching a corresponding
511+ * {@link SelectAction}.
512+ * <p>
513+ * If a {@link IdeSelectActionHandler} is installed on the server, this will
514+ * also eventually invoke {@link #updateSelection(SelectAction)} to update the
515+ * {@link #currentSelection} in this editor object and notify the registered
516+ * selection listeners.
517+ * </p>
518+ */
519+ @ Override
520+ public void setSelection (final ISelection selection ) {
521+ if (!(selection instanceof StructuredSelection )) {
522+ return ;
523+ }
524+
525+ getModelStateOnceInitialized ().thenAccept (modelState -> {
526+ StructuredSelection structuredSelection = (StructuredSelection ) selection ;
527+ List <String > toSelect = toGModelElementStream (structuredSelection ).map (GModelElement ::getId ).collect (toList ());
528+ Set <String > toDeselect = modelState .getIndex ().allIds ();
529+ toDeselect .removeAll (toSelect );
530+ dispatch (new SelectAction (toSelect , new ArrayList <>(toDeselect )));
531+ });
532+ }
533+
534+ /**
535+ * Updates the currently selected elements.
536+ * <p>
537+ * In contrast to {@link #setSelection(ISelection)}, this method does not change
538+ * the selection on the client but only notifies the selection listeners and
539+ * updates the list of currently selected elements in this editor object.
540+ * </p>
541+ * <p>
542+ * This method is usually invoked by the {@link IdeSelectActionHandler}, which
543+ * reacts to the {@link SelectAction} (e.g. triggered by the client on select)
544+ * to update the selection and notify listeners in Eclipse.
545+ * </p>
546+ *
547+ * @param selectAction the {@link SelectAction}
548+ */
549+ public void updateSelection (final SelectAction selectAction ) {
550+ getModelStateOnceInitialized ().thenAccept (modelState -> {
551+ List <String > selectedIds = selectAction .getSelectedElementsIDs ();
552+ List <String > deselectedIds = selectAction .getDeselectedElementsIDs ();
553+ List <GModelElement > selectedGModelElements = toGModelElements (selectedIds , modelState );
554+ List <GModelElement > deselectedGModelElements = toGModelElements (deselectedIds , modelState );
555+ List <GModelElement > selection = toGModelElementStream (currentSelection ).collect (toList ());
556+
557+ selection .removeAll (deselectedGModelElements );
558+ addUnique (selectedGModelElements , selection );
559+
560+ currentSelection = new StructuredSelection (selection );
561+ selectionListener .selectionChanged (new SelectionChangedEvent (this , currentSelection ));
562+ });
563+ }
564+
565+ private void addUnique (final List <GModelElement > fromList , final List <GModelElement > toList ) {
566+ for (GModelElement newSelectedElement : fromList ) {
567+ if (!toList .contains (newSelectedElement )) {
568+ toList .add (newSelectedElement );
569+ }
570+ }
571+ }
572+
573+ @ SuppressWarnings ("unchecked" )
574+ protected Stream <GModelElement > toGModelElementStream (final StructuredSelection selection ) {
575+ return selection .toList ().stream ().filter (GModelElement .class ::isInstance ).map (GModelElement .class ::cast );
576+ }
577+
578+ protected List <GModelElement > toGModelElements (final List <String > ids , final GModelState modelState ) {
579+ return ids .stream ().map (modelState .getIndex ()::get ).flatMap (Optional ::stream ).collect (toList ());
580+ }
581+
457582}
0 commit comments