-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTreeViewerGroup.java
More file actions
1513 lines (1241 loc) · 47.2 KB
/
TreeViewerGroup.java
File metadata and controls
1513 lines (1241 loc) · 47.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*******************************************************************************
* Copyright (C) 2016-2018 Institute of Automation, TU Dresden.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Institute of Automation, TU Dresden - initial API and implementation
******************************************************************************/
package de.tud.et.ifa.agtele.ui.widgets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.Parameterization;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.ui.viewer.ColumnViewerInformationControlToolTipSupport;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.command.CreateChildCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.ui.action.CreateChildAction;
import org.eclipse.emf.edit.ui.action.CreateSiblingAction;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.emf.edit.ui.provider.DecoratingColumLabelProvider;
import org.eclipse.emf.edit.ui.provider.DelegatingStyledCellLabelProvider;
import org.eclipse.emf.edit.ui.provider.DiagnosticDecorator;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.services.IServiceLocator;
import de.tud.et.ifa.agtele.emf.AgteleEcoreUtil;
import de.tud.et.ifa.agtele.resources.BundleContentHelper;
import de.tud.et.ifa.agtele.ui.AgteleUIPlugin;
import de.tud.et.ifa.agtele.ui.emf.edit.action.filter.CreateActionChangeListener;
import de.tud.et.ifa.agtele.ui.emf.edit.action.filter.ICreateActionFilter;
import de.tud.et.ifa.agtele.ui.emf.edit.action.filter.IFilterItemFactory;
import de.tud.et.ifa.agtele.ui.emf.edit.action.filter.ItemProviderCreateActionFilter;
import de.tud.et.ifa.agtele.ui.emf.editor.ActionUtil;
import de.tud.et.ifa.agtele.ui.emf.editor.IExtendedCreateElementAction;
import de.tud.et.ifa.agtele.ui.interfaces.IPersistable;
import de.tud.et.ifa.agtele.ui.listeners.EditMultilineFeatureDoubleClickListener;
import de.tud.et.ifa.agtele.ui.listeners.SelectionListener2;
import de.tud.et.ifa.agtele.ui.providers.StateRestoringViewerContentProvider;
import de.tud.et.ifa.agtele.ui.views.EMFModelHelpView;
import de.tud.et.ifa.agtele.ui.views.EMFModelHelpView.HelpListener;
/**
* A class that represents an SWT {@link Group} containing a {@link FilteredTree filtered tree viewer} and optionally a
* {@link ToolBar}. It supports {@link IPersistable persisting and restoring} the state of the tree viewer (i.e. the
* expanded paths).
*
* @author mfreund
*
*/
public class TreeViewerGroup extends SelectionRestoringFilteredTree implements IPersistable, ISelectionProvider {
protected final String bundleID = AgteleUIPlugin.getPlugin().getSymbolicName();
/**
* This is the adapter factory used to create content and label providers.
*/
protected ComposedAdapterFactory adapterFactory;
/**
* This is the group that contains all other parts.
*/
protected Group group;
/**
* This is the tool bar.
*/
protected ToolBar toolbar;
/**
* This is the label of the group containing all other widgets.
*/
protected String groupText;
/**
* The {@link EditingDomain} for the model to be displayed in this tree viewer. It is, e.g., used to extract labels
* for the elements to be displayed in the tree.
*/
protected EditingDomain editingDomain;
/**
* The {@link IDialogSettings} that are used to persist and restore the state of this viewer.
*
* @see IPersistable
*/
private IDialogSettings dialogSettings;
/**
* The {@link Composite} holding the {@link ToolBar} that displays the various buttons.
*/
private Composite toolbarComposite;
/**
* The options, this instance has been initialized with.
*/
protected TreeViewerGroupOption[] options;
/**
* The sash containing the vertically split elements.
*/
protected SashForm treePaletteSeparator;
/**
* The weights of the treePaletteSeparator
*/
private int[] sashWeights;
protected DisposeListener disposeListener;
/**
* Use this constructor if you want to add one or multiple {@link TreeViewerGroupOption TreeViewerGroupOptions} to
* the viewer.
*
* @param parent
* The parent composite.
* @param adapterFactory
* The adapter factory used to create label and content adapters.
* @param editingDomain
* The editing domain that is used for the viewer.
* @param dialogSettings
* The dialog settings belonging to the editor (e.g. XYZPlugin..getPlugin().getDialogSettings()).
* @param groupText
* The label of the group widget that hold all other widgets. If this is null no surrounding group will
* created.
* @param options
* A set of options that are used to alter the default composition of the TreeViewerGroup
*/
public TreeViewerGroup(Composite parent, ComposedAdapterFactory adapterFactory, EditingDomain editingDomain,
IDialogSettings dialogSettings, String groupText, TreeViewerGroupOption... options) {
super(parent,true,true);
this.parent = parent;
this.groupText = groupText;
this.editingDomain = editingDomain;
this.adapterFactory = adapterFactory;
this.dialogSettings = dialogSettings;
this.options = options == null ? new TreeViewerGroupOption[0] : options;
this.init(SWT.MULTI, new PatternFilter());
}
/**
* The default option to add a collapse all button to the tool bar.
*
* @return a new instance of the TreeViewerGroupToolbarCollapseAllButtonOption
*/
public static TreeViewerGroupToolbarCollapseAllButtonOption TOOLBAR_COLLAPSE_ALL_BUTTON() {
return new TreeViewerGroupToolbarCollapseAllButtonOption();
}
/**
* The default option to add an add button to the tool bar.
*
* @return a new instance of TreeViewerGroupToolbarAddButtonOption
*/
public static TreeViewerGroupToolbarAddButtonOption TOOLBAR_ADD_BUTTON() {
return new TreeViewerGroupToolbarAddButtonOption();
}
/**
* The default option to add the model elements tool palette.
*
* @return a new instance of TreeViewerGroupAddToolPaletteOption
*/
public static TreeViewerGroupAddToolPaletteOption PALETTE_MODEL_ELEMENTS() {
return new TreeViewerGroupAddToolPaletteOption();
}
/**
* The default option to add a toggle editor split vertically button.
*
* @return a new instance of TreeViewerGroupToolbarToggleSplitEditorVerticallyButtonOption
*/
public static TreeViewerGroupToolbarToggleSplitEditorVerticallyButtonOption TOOLBAR_TOGGLE_SPLIT_VERTICALLY_BUTTON() {
return new TreeViewerGroupToolbarToggleSplitEditorVerticallyButtonOption();
}
/**
* The default option to add bind the {@link HelpListener} so that the user can press F1 to open the
* {@link EMFModelHelpView}..
*
* @return a new instance of TreeViewerGroupBindHelpListenerOption
*/
public static TreeViewerGroupBindHelpListenerOption BIND_HELP_LISTENER() {
return new TreeViewerGroupBindHelpListenerOption();
}
/**
* @return a new instance of TreeViewerGroupBindDoubleClickEditMultilineFeatureOption
*/
public static TreeViewerGroupBindDoubleClickEditMultilineFeatureOption BIND_DOUBLE_CLICK_EDIT_MULTILINE_FEATURE_LISTENER() {
return new TreeViewerGroupBindDoubleClickEditMultilineFeatureOption();
}
/**
* Create the filtered tree's controls. This is copied from the standard 'FilteredTree' - changes are only
* introduced in the layout of the filter composite.
*
* @param parent
* @param treeStyle
*/
@Override
protected void createControl(Composite parent, int treeStyle) {
this.disposeListener = e -> {
parent.removeDisposeListener(TreeViewerGroup.this.disposeListener);
TreeViewerGroup.this.dispose();
};
parent.addDisposeListener(this.disposeListener);
// Set the layout for the main composite
if (parent.getLayout() instanceof GridLayout) {
this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
}
GridLayoutFactory.swtDefaults().margins(0, 0).applyTo(this);
// The group to hold everything else.
// only create Group if the groupText is set
// else use a
if (this.groupText != null) {
this.group = new Group(this, SWT.NONE);
this.group.setText(this.groupText);
GridDataFactory.swtDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(this.group);
GridLayoutFactory.swtDefaults().applyTo(this.group);
}
if (this.showFilterControls) {
this.createFilterTools();
this.createToolbar(this.toolbarComposite);
}
List<TreeViewerGroupPaletteOption> paletteOptions = Arrays.asList(this.options).parallelStream()
.filter(i -> i instanceof TreeViewerGroupPaletteOption).map(i -> (TreeViewerGroupPaletteOption) i)
.collect(Collectors.toList());
int paletteCount = 0;
int treeIndex = 0;
// creates the palette controls to the left side of the tree
for (TreeViewerGroupPaletteOption i : paletteOptions) {
if (i.addToLeftSide()) {
if (this.treePaletteSeparator == null) {
this.treePaletteSeparator = new SashForm(this.group == null ? this : this.group, SWT.SMOOTH);
this.treePaletteSeparator.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
}
i.addPaletteControls(this, this.treePaletteSeparator, paletteCount, this.options);
paletteCount += 1;
}
}
treeIndex = paletteCount;
paletteCount += 1;
// create the tree and its composite
if (this.treePaletteSeparator != null) {
this.treeComposite = new Composite(this.treePaletteSeparator, SWT.NONE);
} else {
this.treeComposite = new Composite(this.group == null ? this : this.group, SWT.NONE);
}
GridLayoutFactory.swtDefaults().margins(0, 0).applyTo(this.treeComposite);
GridDataFactory.swtDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(this.treeComposite);
this.createTreeControl(this.treeComposite, treeStyle);
// adds the palettes to the right of the tree
for (TreeViewerGroupPaletteOption i : paletteOptions) {
if (i.addToRightSide()) {
if (this.treePaletteSeparator == null) {
this.treePaletteSeparator = new SashForm(this.group == null ? this : this.group, SWT.SMOOTH);
this.treePaletteSeparator.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
// Move the tree
this.treeComposite.setParent(this.treePaletteSeparator);
}
i.addPaletteControls(this, this.treePaletteSeparator, paletteCount, this.options);
paletteCount += 1;
}
}
// calculate the weights of the sash form
if (this.treePaletteSeparator != null
&& (this.sashWeights == null || this.sashWeights.length != paletteCount)) {
this.sashWeights = new int[paletteCount];
for (int i = 0; i < paletteCount; i += 1) {
this.sashWeights[i] = 1;
}
this.sashWeights[treeIndex] = paletteCount;
this.treePaletteSeparator.setWeights(this.sashWeights);
}
}
/**
* creates the filter controls
*/
protected void createFilterTools() {
// This composite hosts two children: the filter composite and the
// tool bar composite.
this.filterComposite = new Composite(this.group == null ? this : this.group, SWT.NONE);
this.filterComposite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
GridLayoutFactory.swtDefaults().numColumns(2).margins(0, 0).applyTo(this.filterComposite);
// create filter controls that will take up all of the horizontal space
// except the one that is taken by the tool bar
Composite filterBoxComposite = new Composite(this.filterComposite, SWT.BORDER);
filterBoxComposite.setBackground(this.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
filterBoxComposite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
GridLayoutFactory.swtDefaults().numColumns(2).margins(0, 0).applyTo(filterBoxComposite);
filterBoxComposite.setFont(this.parent.getFont());
this.createFilterControls(filterBoxComposite);
// create a toolbar besides the filter controls
this.toolbarComposite = new Composite(this.filterComposite, SWT.NONE);
GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.BEGINNING).applyTo(this.toolbarComposite);
GridLayoutFactory.swtDefaults().margins(0, 0).applyTo(this.toolbarComposite);
}
/**
* Exposes the internal tree composite.
*
* @return The TreeComposite of the TreeViewerGroup
*/
public Composite getTreeComposite() {
return this.treeComposite;
}
/**
* The getter for the {@link #toolbarComposite}.
*
* @return The {@link Composite} holding the {@link ToolBar} that displays the various buttons.
*/
public Composite getToolbar() {
return this.toolbarComposite;
}
/**
* Override the standard method so that default label and content providers based on the adapter factory are
* created.
*
* @param parent
* The parent composite.
* @param style
* SWT style bits used to create the tree viewer.
* @return The created {@link TreeViewer}.
*/
@Override
protected TreeViewer doCreateTreeViewer(Composite parent, int style) {
TreeViewer treeViewer = super.doCreateTreeViewer(parent, style);
treeViewer.setLabelProvider(
new DelegatingStyledCellLabelProvider(new DecoratingColumLabelProvider.StyledLabelProvider(
new AdapterFactoryLabelProvider.StyledLabelProvider(this.adapterFactory, treeViewer),
new DiagnosticDecorator.Styled(this.editingDomain, treeViewer, this.dialogSettings)) {
@Override
public String getToolTipText(Object element) {
String documentation = "";
if (element instanceof EObject && ((EObject) element).eClass() != null) {
documentation = "<b>Element Type: " + ((EObject) element).eClass().getName() + "</b>";
String eClassDoc = EcoreUtil.getDocumentation(((EObject) element).eClass());
if (eClassDoc != null && !eClassDoc.isEmpty()) {
documentation += "<p /><b>Documentation: </b>" + eClassDoc;
}
}
String toolTip = super.getToolTipText(element);
return toolTip == null || toolTip.isEmpty() ? documentation : toolTip + "<p />" + documentation;
}
}));
treeViewer.setContentProvider(new StateRestoringViewerContentProvider(this.adapterFactory, treeViewer));
new ColumnViewerInformationControlToolTipSupport(treeViewer,
new DiagnosticDecorator.Styled.EditingDomainLocationListener(this.editingDomain, treeViewer));
// If necessary, initialize additional options
//
Collection<TreeViewerGroupOption> options = Arrays.asList(this.options).parallelStream()
.filter(o -> o instanceof TreeViewerGroupSelectionViewerOption).collect(Collectors.toList());
for (TreeViewerGroupOption option : options) {
((TreeViewerGroupSelectionViewerOption) option).init(treeViewer, this.adapterFactory, this);
}
return treeViewer;
}
@Override
public boolean isFocusControl() {
//This needs to be overridden in order to enable setting the focus after a model change
return this.getTreeViewer().getControl().isFocusControl();
}
/**
* Returns the tree viewer
*
* @return The {@link TreeViewer}.
*/
public TreeViewer getTreeViewer() {
return this.treeViewer;
}
/**
* This creates a tool bar if necessary.
*
* @param parent
* The parent composite.
*/
protected void createToolbar(Composite parent) {
List<TreeViewerGroupToolbarOption> toolbarOptions = Arrays.asList(this.options).parallelStream()
.filter(i -> i instanceof TreeViewerGroupToolbarOption).map(i -> (TreeViewerGroupToolbarOption) i)
.collect(Collectors.toList());
// Nothing to be done
//
if (toolbarOptions.isEmpty()) {
return;
}
// Create the toolbar
//
this.toolbar = new ToolBar(parent, SWT.NONE);
this.toolbar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
// Create the toolbar controls
//
toolbarOptions.stream().forEach(i -> i.addToolbarControls(this, this.toolbar, this.options));
this.toolbar.pack();
}
@Override
public void persist(IDialogSettings settings) {
// Persist the expanded tree paths of the tree viewer
//
Set<String> paths = new LinkedHashSet<>();
Arrays.asList(this.treeViewer.getExpandedTreePaths()).stream().forEach(path -> {
if (path.getLastSegment() instanceof EObject) {
// use the URI of the eObject as unique identifier
//
paths.add(EcoreUtil.getURI((EObject) path.getLastSegment()).toString());
} else if (path.getLastSegment() instanceof Resource) {
// use the URI of the eObject as unique identifier
//
paths.add(((Resource) path.getLastSegment()).getURI().toString());
} else {
// TODO currently, persisting only works for objects
// representing a real eObject
return;
}
});
settings.put("EXPANDED_TREE_PATHS", paths.toArray(new String[paths.size()]));
// Persist the filter text
//
settings.put("FILTER_TEXT", this.getFilterString() != null ? this.getFilterString() : "");
if (this.treePaletteSeparator != null) {
this.sashWeights = this.treePaletteSeparator.getWeights();
String[] weights = new String[this.sashWeights.length];
for (int i = 0; i < this.sashWeights.length; i += 1) {
weights[i] = Integer.toString(this.sashWeights[i]);
}
settings.put("PALETTE_WEIGHTS", weights);
}
// Persist the various options passed by the user
//
Arrays.asList(this.options).stream().filter(i -> i instanceof TreeViewerGroupPersistableOption)
.forEach(i -> ((TreeViewerGroupPersistableOption) i).persist(settings));
}
@Override
public void restore(IDialogSettings settings) {
// Restore the expanded tree paths of the tree viewer
//
if (settings.getArray("EXPANDED_TREE_PATHS") != null) {
String[] paths = settings.getArray("EXPANDED_TREE_PATHS");
List<Object> expandedList = new ArrayList<>();
for (String path : new LinkedHashSet<String>(Arrays.asList(paths))) {
Object expanded;
/*
* as the URI of an eObject also reflects the containing resource, we can use this to uniquely identify
* an eObject inside a resource set
*/
try {
expanded = this.editingDomain.getResourceSet().getEObject(URI.createURI(path), true);
} catch (Exception e) {
// If the EObject can't be loaded, it may be because it's a
// resource
expanded = this.editingDomain.getResourceSet().getResource(URI.createURI(path), true);
}
if (expanded != null) {
expandedList.add(expanded);
}
}
ITreeContentProvider provider = this.treeViewer.getContentProvider() instanceof ITreeContentProvider ?
(ITreeContentProvider) this.treeViewer.getContentProvider() : null;
List<Object> treeContents = new ArrayList<>();
if (provider != null) {
this.initializeTreeContent(treeContents, provider);
}
// treeContents.forEach(o -> this.treeViewer.setExpandedState(o, false));
ExpandedLoop:
for (Object expanded : expandedList) {
//check if all containers of the expanded elements are expanded as well in order to prevent endless expansion of nodes (bug in underlying treeviewer class)
if (expanded instanceof Resource) {
this.treeViewer.setExpandedState(expanded, true);
} else if (expanded instanceof EObject) {
EObject expandedObject = (EObject) expanded;
for (EObject container : AgteleEcoreUtil.getAllContainers(expandedObject)) {
if (provider != null && treeContents.contains(container) && !expandedList.contains(container)) {
continue ExpandedLoop;
}
}
//do not check resource expanded state in order to
this.treeViewer.setExpandedState(expanded, true);
}
}
}
// Restore the filter text
//
String filterText = settings.get("FILTER_TEXT");
if (filterText != null && !filterText.isEmpty()) {
this.setFilterText(filterText);
}
try {
String[] weights = settings.getArray("PALETTE_WEIGHTS");
if (weights != null) {
this.sashWeights = new int[weights.length];
for (int i = 0; i < weights.length; i += 1) {
this.sashWeights[i] = new Integer(weights[i]);
}
if (this.treePaletteSeparator != null && !this.treePaletteSeparator.isDisposed()) {
this.treePaletteSeparator.setWeights(this.sashWeights);
}
}
} catch (Exception e) {
// do nothing, default weights will kick in
}
for (TreeViewerGroupOption i : this.options) {
if (i instanceof TreeViewerGroupPersistableOption) {
((TreeViewerGroupPersistableOption) i).restore(settings);
}
}
}
@SuppressWarnings("unchecked")
protected void initializeTreeContent(List<Object> treeContents, ITreeContentProvider provider) {
if (this.treeViewer.getInput() instanceof Collection) {
treeContents.addAll((Collection<? extends Object>)this.treeViewer.getInput());
} else if (this.treeViewer.getInput().getClass().isArray()) {
treeContents.addAll(Arrays.asList(this.treeViewer.getInput()));
} else {
treeContents.add(this.treeViewer.getInput());
}
for (Object o : new ArrayList<>(treeContents)) {
this.addNodes(treeContents, provider, o);
}
}
protected void addNodes(List<Object> treeContents, ITreeContentProvider provider, Object obj) {
for (Object o : provider.getChildren(obj)) {
if (!treeContents.contains(o)) {
treeContents.add(o);
this.addNodes(treeContents, provider, o);
}
}
}
/**
*
*/
@Override
public void dispose() {
Arrays.asList(this.options).stream().forEach(TreeViewerGroupOption::dispose);
}
@Override
public void addSelectionChangedListener(ISelectionChangedListener listener) {
this.treeViewer.addSelectionChangedListener(listener);
}
@Override
public ISelection getSelection() {
return this.treeViewer.getSelection();
}
@Override
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
this.treeViewer.removeSelectionChangedListener(listener);
}
@Override
public void setSelection(ISelection selection) {
this.treeViewer.setSelection(selection);
}
/**
* Can be anything, that alters the TreeViewerGroup
*
* @author Lukas
*/
public static interface TreeViewerGroupOption {
/**
* Disposes the created UI elements and removes created event listeners from other elements.
*/
public void dispose();
}
public static interface TreeViewerGroupSelectionViewerOption extends TreeViewerGroupOption {
default public void init(TreeViewer viewer, AdapterFactory factory, TreeViewerGroup group) {}
}
/**
* A ToolbarOption alters the contents of the Toolbar.
*
* @author Lukas
*/
public static interface TreeViewerGroupToolbarOption extends TreeViewerGroupOption {
/**
* Add some Controls to the ToolBar.
*
* @param group
* The containing TreeViewerGroup
* @param toolbar
* The toolbar to manipulate
* @param options
* All Options the TreeViewerGroup has been initialized with.
*/
public default void addToolbarControls(TreeViewerGroup group, ToolBar toolbar,
TreeViewerGroupOption[] options) {
}
}
/**
* A Palette Option can alter the side content next to the actual tree.
*
* @author Lukas
*/
public static interface TreeViewerGroupPaletteOption extends TreeViewerGroupOption {
/**
* Add some Controls to the ToolBar.
*
* @param group
* The containing TreeViewerGroup
* @param sash
* The sash to add this element to
* @param index
* The index of this palette in the sash
* @param options
* All Options the TreeViewerGroup has been initialized with.
*/
public default void addPaletteControls(TreeViewerGroup group, SashForm sash, int index,
TreeViewerGroupOption[] options) {
}
/**
* Whether content shall be added to the left side
*
* @return Return true, if the palette shall be added to the left side.
*/
public default boolean addToLeftSide() {
return false;
}
/**
* Whether content shall be added to the left side
*
* @return Return true, if the palette shall be added to the right side.
*/
public default boolean addToRightSide() {
return false;
}
}
/**
* An option that adds info to the persisted group data
*
* @author Lukas
*/
public static interface TreeViewerGroupPersistableOption extends TreeViewerGroupOption, IPersistable {
}
/**
* An option to add a collapse all button to the toolbar.
*
* @author Lukas
*/
public static class TreeViewerGroupToolbarCollapseAllButtonOption implements TreeViewerGroupToolbarOption {
/**
* The added item.
*/
protected ToolItem item;
@Override
public void addToolbarControls(TreeViewerGroup group, ToolBar toolbar, TreeViewerGroupOption[] options) {
this.item = new ToolItem(toolbar, SWT.PUSH | SWT.TRAIL);
this.item.setImage(BundleContentHelper.getBundleImage(group.bundleID, "icons/collapse_all.gif"));
this.item.setToolTipText("Collapse Tree");
this.item.addSelectionListener((SelectionListener2) e -> group.getViewer().collapseAll());
}
@Override
public void dispose() {
this.item.getImage().dispose();
this.item.dispose();
}
}
/**
* An option to add a split editor vertically button to the toolbar.
*
* @author Lukas
*/
public static class TreeViewerGroupToolbarToggleSplitEditorVerticallyButtonOption
implements TreeViewerGroupToolbarOption {
/**
* The added item.
*/
protected ToolItem item;
@Override
public void addToolbarControls(TreeViewerGroup group, ToolBar toolbar, TreeViewerGroupOption[] options) {
this.item = new ToolItem(toolbar, SWT.PUSH | SWT.TRAIL);
this.item.setImage(BundleContentHelper.getBundleImage(group.bundleID, "icons/th_horizontal.gif"));
this.item.setToolTipText("Toggle Split Editor");
this.item.addSelectionListener((SelectionListener2) e -> {
ICommandService commandService = ((IServiceLocator) PlatformUI.getWorkbench())
.getService(ICommandService.class);
Command command = commandService.getCommand("org.eclipse.ui.window.splitEditor");
IHandlerService handlerService = ((IServiceLocator) PlatformUI.getWorkbench())
.getService(IHandlerService.class);
try {
Parameterization[] params = new Parameterization[] {
new Parameterization(command.getParameter("Splitter.isHorizontal"), "false") };
ParameterizedCommand parametrizedCommand = new ParameterizedCommand(command, params);
handlerService.executeCommand(parametrizedCommand, null);
} catch (ExecutionException | NotDefinedException | NotEnabledException | NotHandledException e1) {
e1.printStackTrace();
}
});
}
@Override
public void dispose() {
this.item.getImage().dispose();
this.item.dispose();
}
}
/**
* Adds an Add Button to the Toolbar.
*
* @author Lukas
*/
public static class TreeViewerGroupToolbarAddButtonOption implements TreeViewerGroupToolbarOption {
/**
* The added item.
*/
protected ToolItem item;
protected TreeViewerGroup group;
protected AddDropDownSelectionListener listener;
/**
* Add some Controls to the ToolBar.
*
* @param toolbar
* The toolbar to manipulate
* @param options
* All Options the TreeViewerGroup has been initialized with.
*/
@Override
public void addToolbarControls(TreeViewerGroup group, ToolBar toolbar, TreeViewerGroupOption[] options) {
this.group = group;
this.item = new ToolItem(toolbar, SWT.DROP_DOWN);
this.item.setImage(BundleContentHelper.getBundleImage(group.bundleID, "icons/add_obj.gif"));
this.item.setToolTipText("Add Sibling of Same Type");
this.listener = this.createAddDropDownSelectionListener(this.item);
this.item.addSelectionListener(this.listener);
}
protected AddDropDownSelectionListener createAddDropDownSelectionListener(ToolItem item) {
return new AddDropDownSelectionListener(item);
}
/**
* A {@link SelectionAdapter} that operates on a {@link ToolItem} and allows the user to add items based on the
* element currently selected in the tree.
*
* @author mfreund
*/
public class AddDropDownSelectionListener extends SelectionAdapter {
/**
* The {@link MenuManager} that creates the menu with the various options for adding an element that can be
* selected by the user.
*/
private MenuManager menuManager;
/**
* This creates an instance.
*
* @param dropdown
* The {@link ToolItem} on that this listener listens.
*/
public AddDropDownSelectionListener(ToolItem dropdown) {
this.menuManager = new MenuManager();
this.menuManager.createContextMenu(dropdown.getParent());
}
@Override
public void widgetSelected(SelectionEvent event) {
if (event.detail == SWT.ARROW) {
ToolItem item = (ToolItem) event.widget;
Rectangle rect = item.getBounds();
Point pt = item.getParent().toDisplay(new Point(rect.x, rect.y));
this.createMenu();
this.menuManager.getMenu().setLocation(pt.x, pt.y + rect.height);
this.menuManager.getMenu().setVisible(true);
} else {
this.addDefaultElement();
}
}
/**
* This determines the currently selected element and adds an element of the same type to its parent.
*/
private void addDefaultElement() {
ISelection selection = TreeViewerGroupToolbarAddButtonOption.this.group.treeViewer.getSelection();
if (selection.isEmpty() || !(selection instanceof StructuredSelection)) {
// nothing to be done
return;
}
StructuredSelection structuredSelection = (StructuredSelection) selection;
Object selectedObject = structuredSelection.getFirstElement();
if (!(selectedObject instanceof EObject)) {
// nothing to be done
return;
}
// A command that will create a new eObject that is of the same
// type of the selected eObject. The newly created object will
// then
// be added to the parent.
CreateChildCommand command = new CreateChildCommand(
TreeViewerGroupToolbarAddButtonOption.this.group.editingDomain,
((EObject) selectedObject).eContainer(), ((EObject) selectedObject).eContainingFeature(),
EcoreUtil.create(((EObject) selectedObject).eClass()), null);
// Execute the command and set the selection of the viewer to
// the
// newly created object.
TreeViewerGroupToolbarAddButtonOption.this.group.editingDomain.getCommandStack().execute(command);
TreeViewerGroupToolbarAddButtonOption.this.group.treeViewer
.setSelection(new StructuredSelection(command.getResult().toArray()));
}
/**
* This creates a new menu based on the currently selected element that allows to create children and
* siblings.
*/
private void createMenu() {
// Clear the context menu
//
this.menuManager.removeAll();
ISelection selection = TreeViewerGroupToolbarAddButtonOption.this.group.treeViewer.getSelection();
if (!(selection instanceof IStructuredSelection) || ((IStructuredSelection) selection).size() > 1) {
// nothing to be done
return;
}
List<CreateChildAction> createChildActions;
List<CreateSiblingAction> createSiblingActions = new ArrayList<>();
if (((IStructuredSelection) selection).isEmpty()) {
// if nothing is selected,we manually select the viewer
// input; this will allow to add the
// top level elements in this viewer
//
try {