1 | package de.uka.ipd.sdq.dsexplore.launch; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.Collections; |
5 | import java.util.HashMap; |
6 | import java.util.Iterator; |
7 | import java.util.List; |
8 | import java.util.Map; |
9 | import java.util.Map.Entry; |
10 | |
11 | import org.eclipse.core.runtime.CoreException; |
12 | import org.eclipse.core.runtime.IConfigurationElement; |
13 | import org.eclipse.core.runtime.IExtension; |
14 | import org.eclipse.debug.core.ILaunchConfiguration; |
15 | import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; |
16 | import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; |
17 | import org.eclipse.debug.ui.ILaunchConfigurationTab; |
18 | import org.eclipse.debug.ui.ILaunchConfigurationTabGroup; |
19 | import org.eclipse.swt.SWT; |
20 | import org.eclipse.swt.custom.CTabFolder; |
21 | import org.eclipse.swt.custom.StackLayout; |
22 | import org.eclipse.swt.events.SelectionAdapter; |
23 | import org.eclipse.swt.events.SelectionEvent; |
24 | import org.eclipse.swt.layout.GridData; |
25 | import org.eclipse.swt.layout.GridLayout; |
26 | import org.eclipse.swt.widgets.Combo; |
27 | import org.eclipse.swt.widgets.Composite; |
28 | |
29 | import de.uka.ipd.sdq.dsexplore.helper.ExtensionHelper; |
30 | import de.uka.ipd.sdq.dsexplore.launch.DSEConstantsContainer.QualityAttribute; |
31 | import de.uka.ipd.sdq.workflow.launchconfig.tabs.TabHelper; |
32 | |
33 | /** |
34 | * This class represents the launch configuration tab "Analysis Method". It |
35 | * provides a selection of the concrete analysis method to be used in design |
36 | * exploration runs. |
37 | * <p> |
38 | * Also the represented tab serves as container for tabs provided by a concrete |
39 | * analysis method. By providing tabs, a analysis method can contribute controls |
40 | * to the GUI whereby further configuration can be offered. |
41 | * <p> |
42 | * The available analysis methods are automatically discovered by the eclipse |
43 | * extension point mechanism. |
44 | * |
45 | * @author pmerkle |
46 | * |
47 | */ |
48 | public class DSEAnalysisMethodTab extends AbstractLaunchConfigurationTab { |
49 | |
50 | private StackLayout layout; |
51 | |
52 | private Composite tabFolderContainer; |
53 | |
54 | private Combo methodCombo; |
55 | |
56 | private boolean methodComboEnabled = true; |
57 | |
58 | private Map<String, IConfigurationElement> nameExtensionElementMap; |
59 | |
60 | private Map<IConfigurationElement, CTabFolder> extensionElementTabFolderMap; |
61 | |
62 | private Map<IConfigurationElement, ILaunchConfigurationTabGroup> extensionElementTabGroupMap; |
63 | |
64 | private AnalysisMethodListener listener = new AnalysisMethodListener(); |
65 | |
66 | private QualityAttribute qualityAttributeId; |
67 | |
68 | public DSEAnalysisMethodTab(QualityAttribute qualityAttribute) { |
69 | super(); |
70 | |
71 | //XXX here not the dimension (e.g. response time) should be the name but the quality attribute (e.g. performance), because one analysis approach can determine several aspects (dimensions) of its quality attribute. |
72 | this.qualityAttributeId = qualityAttribute; |
73 | } |
74 | |
75 | /** |
76 | * {@inheritDoc} |
77 | */ |
78 | @Override |
79 | public String getId(){ |
80 | return this.qualityAttributeId.getName(); |
81 | } |
82 | |
83 | /** |
84 | * {@inheritDoc} |
85 | */ |
86 | @Override |
87 | public void createControl(Composite parent) { |
88 | List<IExtension> extensions = ExtensionHelper.loadAnalysisExtensions(qualityAttributeId); |
89 | |
90 | // Map extension elements to their analysis method names |
91 | nameExtensionElementMap = new HashMap<String, IConfigurationElement>(); |
92 | for (IExtension ext : extensions) { |
93 | IConfigurationElement[] elements = ext.getConfigurationElements(); |
94 | for (IConfigurationElement element : elements) { |
95 | String name = loadAnalysisMethodName(element); |
96 | nameExtensionElementMap.put(name, element); |
97 | } |
98 | } |
99 | |
100 | Composite container = new Composite(parent, SWT.NONE); |
101 | setControl(container); |
102 | container.setLayout(new GridLayout(1, true)); |
103 | |
104 | List<String> methodNames = loadAnalysisMethodNames(extensions); |
105 | Collections.sort(methodNames); |
106 | |
107 | //methodNames.add(DSEConstantsContainer.NONE); |
108 | methodCombo = new Combo(container, SWT.READ_ONLY); |
109 | methodCombo.setItems(methodNames.toArray(methodCombo.getItems())); |
110 | methodCombo.addSelectionListener(listener); |
111 | methodCombo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); |
112 | |
113 | tabFolderContainer = new Composite(container, SWT.NONE); |
114 | layout = new StackLayout(); |
115 | tabFolderContainer.setLayout(layout); |
116 | tabFolderContainer.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true)); |
117 | |
118 | // create tab folders from tab groups provided by available analysis extension elements |
119 | extensionElementTabFolderMap = new HashMap<IConfigurationElement, CTabFolder>(); |
120 | Iterator<Entry<IConfigurationElement, ILaunchConfigurationTabGroup>> it = getExtensionElementTabGroupMap() |
121 | .entrySet().iterator(); |
122 | while (it.hasNext()) { |
123 | Entry<IConfigurationElement, ILaunchConfigurationTabGroup> entry = it.next(); |
124 | IConfigurationElement element = entry.getKey(); |
125 | ILaunchConfigurationTabGroup tabGroup = entry.getValue(); |
126 | |
127 | CTabFolder tabFolder = TabHelper.createTabFolder(tabGroup, |
128 | getLaunchConfigurationDialog(), |
129 | getLaunchConfigurationDialog().getMode(), |
130 | tabFolderContainer, SWT.BORDER | SWT.FLAT); |
131 | |
132 | // Map tab folder to their corresponding extension element |
133 | extensionElementTabFolderMap.put(element, tabFolder); |
134 | } |
135 | } |
136 | |
137 | /** |
138 | * Returns a mapping between analysis extension elements and their associated tab |
139 | * groups. |
140 | * <p> |
141 | * At first invocation, the method loads all tab groups provided by the |
142 | * available analysis extension elements. Also creates the tabs associated with each |
143 | * tab group. |
144 | * |
145 | * @return |
146 | */ |
147 | private Map<IConfigurationElement, ILaunchConfigurationTabGroup> getExtensionElementTabGroupMap() { |
148 | if (extensionElementTabGroupMap == null) { |
149 | extensionElementTabGroupMap = new HashMap<IConfigurationElement, ILaunchConfigurationTabGroup>(); |
150 | |
151 | List<IExtension> extensions = ExtensionHelper.loadAnalysisExtensions(qualityAttributeId); |
152 | for (IExtension ext : extensions) { |
153 | try { |
154 | // Obtain all extension elements |
155 | IConfigurationElement[] elements = ext.getConfigurationElements(); |
156 | for (IConfigurationElement element : elements) { |
157 | ILaunchConfigurationTabGroup tabGroup = (ILaunchConfigurationTabGroup) ExtensionHelper |
158 | .loadExecutableAttribute(element, "launchConfigContribution"); |
159 | // create contained tabs |
160 | tabGroup.createTabs(getLaunchConfigurationDialog(), |
161 | getLaunchConfigurationDialog().getMode()); |
162 | extensionElementTabGroupMap.put(element, tabGroup); |
163 | } |
164 | |
165 | } catch (CoreException e) { |
166 | // TODO Auto-generated catch block |
167 | e.printStackTrace(); |
168 | } |
169 | } |
170 | } |
171 | |
172 | return extensionElementTabGroupMap; |
173 | } |
174 | |
175 | /** |
176 | * Displays the tab folder for the analysis method represented by the passed |
177 | * String. |
178 | * |
179 | * @param name |
180 | * the analysis method name specified by the "name"-attribute of |
181 | * the extension element |
182 | */ |
183 | private void setVisibleMethodOptions(String name) { |
184 | IConfigurationElement selElement = nameExtensionElementMap.get(name); |
185 | CTabFolder selTabFolder = extensionElementTabFolderMap.get(selElement); |
186 | layout.topControl = selTabFolder; |
187 | tabFolderContainer.layout(); |
188 | |
189 | } |
190 | |
191 | /** |
192 | * Loads the names of all analysis methods represented by the passed |
193 | * extensions. |
194 | * |
195 | * @param extensions |
196 | * @return |
197 | */ |
198 | private List<String> loadAnalysisMethodNames(List<IExtension> extensions) { |
199 | List<String> names = new ArrayList<String>(); |
200 | for (int i=0; i < extensions.size(); i++) { |
201 | IExtension extension = extensions.get(i); |
202 | IConfigurationElement[] elements = extension.getConfigurationElements(); |
203 | for (IConfigurationElement element : elements) { |
204 | if (element.getName().equals("analysis")) { |
205 | names.add(element.getAttribute("name")); |
206 | } |
207 | } |
208 | } |
209 | |
210 | return names; |
211 | } |
212 | |
213 | /** |
214 | * Loads the name of a single analysis method represented by the passed |
215 | * extension element. |
216 | * |
217 | * @param extension element |
218 | * @return the analysis method's name; null if the name attribute is not set. |
219 | */ |
220 | private String loadAnalysisMethodName(IConfigurationElement element) { |
221 | return element.getAttribute("name"); |
222 | } |
223 | |
224 | |
225 | /** |
226 | * {@inheritDoc} |
227 | */ |
228 | @Override |
229 | public String getName() { |
230 | return this.qualityAttributeId.getPrettyName() + " Analysis Method"; |
231 | } |
232 | |
233 | /** |
234 | * {@inheritDoc} |
235 | */ |
236 | @Override |
237 | public void initializeFrom(ILaunchConfiguration configuration) { |
238 | try{ |
239 | String method = configuration.getAttribute(DSEConstantsContainer.getAnalysisMethod(this.qualityAttributeId), |
240 | DSEConstantsContainer.NONE); // TODO: Set default string for analysis method |
241 | String[] items = methodCombo.getItems(); |
242 | for (int i=0; i<items.length; i++){ |
243 | String str = items[i]; |
244 | if (str.equals(method)){ |
245 | methodCombo.select(i); |
246 | if(methodComboEnabled) { |
247 | setVisibleMethodOptions(method); |
248 | } else { |
249 | setVisibleMethodOptions(DSEConstantsContainer.NONE); |
250 | } |
251 | } |
252 | } |
253 | } catch(CoreException e){ |
254 | methodCombo.select(0); |
255 | } |
256 | |
257 | Iterator<Entry<IConfigurationElement, ILaunchConfigurationTabGroup>> it = getExtensionElementTabGroupMap() |
258 | .entrySet().iterator(); |
259 | while(it.hasNext()) { |
260 | it.next().getValue().initializeFrom(configuration); |
261 | } |
262 | } |
263 | |
264 | /** |
265 | * {@inheritDoc} |
266 | */ |
267 | @Override |
268 | public void performApply(ILaunchConfigurationWorkingCopy configuration) { |
269 | configuration.setAttribute(DSEConstantsContainer.getAnalysisMethod(this.qualityAttributeId), methodCombo.getText()); |
270 | |
271 | // delegate performApply to subtabs. Pay attention to delegate only to |
272 | // those tabs that are part of the selected analysis method tab group. |
273 | // Otherwise the local performApply methods will mutually override their |
274 | // configuration values if the different tab groups contain equal tabs. |
275 | String methodStr = methodCombo.getText(); |
276 | ILaunchConfigurationTabGroup tabGroup = getExtensionElementTabGroupMap() |
277 | .get(nameExtensionElementMap.get(methodStr)); |
278 | if (tabGroup != null) { |
279 | tabGroup.performApply(configuration); |
280 | } |
281 | } |
282 | |
283 | /** |
284 | * {@inheritDoc} |
285 | */ |
286 | @Override |
287 | public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { |
288 | // Set the first discovered analysis extension element as default analysis method |
289 | List<IExtension> extensions = ExtensionHelper.loadAnalysisExtensions(qualityAttributeId); |
290 | |
291 | Iterator<Entry<IConfigurationElement, ILaunchConfigurationTabGroup>> it = getExtensionElementTabGroupMap() |
292 | .entrySet().iterator(); |
293 | while (it.hasNext()) { |
294 | it.next().getValue().setDefaults(configuration); |
295 | } |
296 | |
297 | if (extensions.size() > 0) { |
298 | IConfigurationElement defaultElement = extensions.get(0).getConfigurationElements()[0]; |
299 | configuration.setAttribute(DSEConstantsContainer.getAnalysisMethod(this.qualityAttributeId), |
300 | loadAnalysisMethodName(defaultElement)); |
301 | } else { |
302 | configuration.setAttribute(DSEConstantsContainer.getAnalysisMethod(this.qualityAttributeId), |
303 | DSEConstantsContainer.NONE); |
304 | } |
305 | |
306 | |
307 | |
308 | } |
309 | |
310 | @Override |
311 | public boolean isValid(ILaunchConfiguration launchConfig) { |
312 | // Check whether an available analysis method is selected |
313 | String methodStr = methodCombo.getText(); |
314 | IConfigurationElement methodElement = nameExtensionElementMap.get(methodStr); |
315 | if (methodElement == null && !methodStr.equals(DSEConstantsContainer.NONE)) { |
316 | setErrorMessage("Choose an analysis method."); |
317 | return false; |
318 | } |
319 | |
320 | // delegate validation to subtabs |
321 | ILaunchConfigurationTabGroup tabGroup = getExtensionElementTabGroupMap() |
322 | .get(nameExtensionElementMap.get(methodStr)); |
323 | if (tabGroup != null) { |
324 | ILaunchConfigurationTab[] tabs = tabGroup.getTabs(); |
325 | for (ILaunchConfigurationTab tab : tabs) { |
326 | boolean valid = tab.isValid(launchConfig); |
327 | if (!valid) { |
328 | // treat sub tabs' errors as own errors |
329 | if (tab.getErrorMessage() != null) { |
330 | setErrorMessage("[" + tab.getName() + "]: " |
331 | + tab.getErrorMessage()); |
332 | } |
333 | return false; |
334 | } |
335 | } |
336 | } |
337 | |
338 | setErrorMessage(null); |
339 | return true; |
340 | } |
341 | |
342 | @Override |
343 | public void activated(ILaunchConfigurationWorkingCopy workingCopy) { |
344 | // Leave this method empty to prevent unnecessary invocation of |
345 | // initializeFrom() and multiple resulting invocations of |
346 | // performApply(). |
347 | } |
348 | |
349 | @Override |
350 | public void deactivated(ILaunchConfigurationWorkingCopy workingCopy) {} |
351 | |
352 | public void deactivate(){ |
353 | |
354 | if(!methodComboEnabled) { |
355 | return; |
356 | } |
357 | this.methodCombo.removeAll(); |
358 | this.methodCombo.add(DSEConstantsContainer.NONE); |
359 | this.methodCombo.select(0); |
360 | methodCombo.setEnabled(false); |
361 | setVisibleMethodOptions(DSEConstantsContainer.NONE); |
362 | methodComboEnabled = false; |
363 | } |
364 | |
365 | public void activate(List<IExtension> extensions){ |
366 | // List<IExtension> extensions = ExtensionHelper.loadAnalysisExtensions(qualityAttribute); |
367 | // this.methodCombo.removeAll(); |
368 | // List<String> methodNames = loadAnalysisMethodNames(extensions); |
369 | // Collections.sort(methodNames); |
370 | // String[] items = methodNames.toArray(methodCombo.getItems()); |
371 | // methodCombo.setItems(items); |
372 | // this.methodCombo.select(0); |
373 | |
374 | List<String> methodNames = loadAnalysisMethodNames(extensions); |
375 | Collections.sort(methodNames); |
376 | |
377 | methodCombo.setItems(methodNames.toArray(new String[1])); |
378 | |
379 | if(methodComboEnabled) { |
380 | return; |
381 | } |
382 | |
383 | methodCombo.setEnabled(true); |
384 | int selection = methodCombo.getSelectionIndex(); |
385 | if(methodCombo.getSelectionIndex()> -1) { |
386 | setVisibleMethodOptions(methodCombo.getItem(selection)); |
387 | } |
388 | methodComboEnabled = true; |
389 | } |
390 | |
391 | private class AnalysisMethodListener extends SelectionAdapter { |
392 | |
393 | @Override |
394 | public void widgetSelected(SelectionEvent e) { |
395 | String selectedText = ((Combo)e.getSource()).getText(); |
396 | IConfigurationElement selElement = nameExtensionElementMap.get(selectedText); |
397 | if (selElement != layout.topControl) { |
398 | setVisibleMethodOptions(selectedText); |
399 | updateLaunchConfigurationDialog(); |
400 | } |
401 | } |
402 | |
403 | } |
404 | |
405 | } |