Make project selector handle MachineContexts and small improvements
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / nature / MachineContextSwtTools.java
1 package net.mograsim.plugin.nature;
2
3 import java.util.Collections;
4 import java.util.HashSet;
5 import java.util.Map;
6 import java.util.Optional;
7 import java.util.Set;
8 import java.util.function.Consumer;
9 import java.util.function.Function;
10
11 import org.eclipse.core.resources.IProject;
12 import org.eclipse.jface.viewers.ComboViewer;
13 import org.eclipse.jface.viewers.IStructuredContentProvider;
14 import org.eclipse.jface.viewers.LabelProvider;
15 import org.eclipse.jface.viewers.StructuredSelection;
16 import org.eclipse.jface.viewers.ViewerComparator;
17 import org.eclipse.swt.SWT;
18 import org.eclipse.swt.widgets.Combo;
19 import org.eclipse.swt.widgets.Composite;
20 import org.eclipse.swt.widgets.Display;
21
22 import net.mograsim.machine.MachineDefinition;
23 import net.mograsim.machine.MachineRegistry;
24
25 public final class MachineContextSwtTools
26 {
27         private static final Map<String, MachineDefinition> INSTALLED_MACHINES = MachineRegistry.getInstalledMachines();
28         private static final Map<IProject, MachineContext> PROJECT_MACHINE_CONTEXTS = ProjectMachineContext.getAllProjectMachineContexts();
29
30         private MachineContextSwtTools()
31         {
32                 // not instantiable
33         }
34
35         public static MachineCombo createMachineSelector(Composite parent, int style)
36         {
37                 return new MachineCombo(parent, style);
38         }
39
40         public static MograsimProjectCombo createMograsimProjectSelector(Composite parent, int style)
41         {
42                 return new MograsimProjectCombo(parent, style);
43         }
44
45         public abstract static class AdvancedCombo<T>
46         {
47                 final ComboViewer combo;
48                 private Set<Consumer<T>> listeners;
49
50                 public AdvancedCombo(Composite parent, Function<T, String> labelProvider)
51                 {
52                         this(parent, SWT.NONE, labelProvider);
53                 }
54
55                 public AdvancedCombo(Composite parent, int style, Function<T, String> labelProvider)
56                 {
57                         listeners = Collections.synchronizedSet(new HashSet<>());
58                         combo = new ComboViewer(parent, style);
59                         combo.addSelectionChangedListener(e -> updateSelection());
60                         combo.setComparator(new ViewerComparator());
61                         combo.setLabelProvider(new LabelProvider()
62                         {
63                                 @SuppressWarnings("unchecked")
64                                 @Override
65                                 public String getText(Object element)
66                                 {
67                                         try
68                                         {
69                                                 return labelProvider.apply((T) element);
70                                         }
71                                         catch (ClassCastException e)
72                                         {
73                                                 return "Invalid Element: " + e.getLocalizedMessage();
74                                         }
75                                 }
76                         });
77                 }
78
79                 public final ComboViewer getCombo()
80                 {
81                         return combo;
82                 }
83
84                 public boolean setSelection(T newSelected)
85                 {
86                         if (newSelected == null)
87                                 combo.setSelection(new StructuredSelection(), true);
88                         else
89                                 combo.setSelection(new StructuredSelection(newSelected), true); // TODO: can this cause errors or other problems?
90                         return isValidSelection();
91                 }
92
93                 @SuppressWarnings("unchecked")
94                 public T getSelection()
95                 {
96                         return (T) combo.getStructuredSelection().getFirstElement();
97                 }
98
99                 private void updateSelection()
100                 {
101                         T active = getSelection();
102                         listeners.forEach(l -> l.accept(active));
103                 }
104
105                 public final void addListener(Consumer<T> listener)
106                 {
107                         listeners.add(listener);
108                 }
109
110                 public final void removeListener(Consumer<T> listener)
111                 {
112                         listeners.remove(listener);
113                 }
114
115                 public void refreshContent()
116                 {
117                         Display.getDefault().asyncExec(combo::refresh);
118                 }
119
120                 public abstract boolean isValidSelection();
121         }
122
123         public static class MachineCombo extends AdvancedCombo<MachineDefinition>
124         {
125                 private static final Set<MachineCombo> machineComboListeners = Collections.synchronizedSet(new HashSet<>());
126
127                 static
128                 {
129                         MachineRegistry.addMachineRegistryListener(newMap -> machineComboListeners.forEach(AdvancedCombo::refreshContent));
130                 }
131
132                 public MachineCombo(Composite parent)
133                 {
134                         this(parent, SWT.NONE);
135                 }
136
137                 public MachineCombo(Composite parent, int style)
138                 {
139                         super(parent, style, MachineDefinition::getId);
140                         combo.setContentProvider(new IStructuredContentProvider()
141                         {
142                                 @Override
143                                 public void dispose()
144                                 {
145                                         machineComboListeners.remove(MachineCombo.this);
146                                 }
147
148                                 @Override
149                                 public Object[] getElements(Object inputElement)
150                                 {
151                                         return INSTALLED_MACHINES.values().toArray();
152                                 }
153                         });
154                         combo.setInput(this);
155                         machineComboListeners.add(this);
156                 }
157
158                 @Override
159                 public boolean isValidSelection()
160                 {
161                         MachineDefinition md = super.getSelection();
162                         if (md == null)
163                                 return false;
164                         return MachineRegistry.getMachine(md.getId()) != null;
165                 }
166         }
167
168         public static class MograsimProjectCombo extends AdvancedCombo<MachineContext>
169         {
170                 private static final Set<MograsimProjectCombo> projectComboListeners = Collections.synchronizedSet(new HashSet<>());
171
172                 static
173                 {
174                         ProjectMachineContext.addProjectContextListener(projectEvent -> projectComboListeners.forEach(AdvancedCombo::refreshContent));
175                 }
176
177                 public MograsimProjectCombo(Composite parent)
178                 {
179                         this(parent, SWT.NONE);
180                 }
181
182                 public MograsimProjectCombo(Composite parent, int style)
183                 {
184                         super(parent, style, mc -> mc.getProject().getName());
185                         combo.setContentProvider(new IStructuredContentProvider()
186                         {
187                                 @Override
188                                 public void dispose()
189                                 {
190                                         projectComboListeners.remove(MograsimProjectCombo.this);
191                                 }
192
193                                 @Override
194                                 public Object[] getElements(Object inputElement)
195                                 {
196                                         return PROJECT_MACHINE_CONTEXTS.values().stream().filter(MachineContext::isCurrentyValid).toArray();
197                                 }
198                         });
199                         combo.setInput(this);
200                         projectComboListeners.add(this);
201                 }
202
203                 @Override
204                 public boolean isValidSelection()
205                 {
206                         MachineContext mc = super.getSelection();
207                         if (mc == null)
208                                 return false;
209                         return mc.isCurrentyValid();
210                 }
211         }
212
213         /**
214          * XXX: is this now of no use?
215          */
216         static Optional<String> getSelection(Combo c)
217         {
218                 int selectionIndex = c.getSelectionIndex();
219                 if (selectionIndex == -1)
220                         return Optional.empty();
221                 return Optional.of(c.getItem(selectionIndex));
222         }
223 }