source: trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/ShowUsabilityEvaluationResultDialog.java @ 1920

Last change on this file since 1920 was 1920, checked in by pharms, 9 years ago
  • extension with further smell detections
  • may not fully work. But Hudson is more happy because compile errors should be gone
File size: 19.6 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.ui.swt;
16
17import java.awt.GraphicsDevice;
18import java.awt.GraphicsEnvironment;
19import java.util.ArrayList;
20import java.util.Collection;
21import java.util.HashMap;
22import java.util.LinkedList;
23import java.util.List;
24import java.util.Map;
25
26import org.eclipse.swt.SWT;
27import org.eclipse.swt.custom.SashForm;
28import org.eclipse.swt.custom.StyleRange;
29import org.eclipse.swt.custom.StyledText;
30import org.eclipse.swt.events.SelectionAdapter;
31import org.eclipse.swt.events.SelectionEvent;
32import org.eclipse.swt.events.ShellAdapter;
33import org.eclipse.swt.events.ShellEvent;
34import org.eclipse.swt.graphics.Font;
35import org.eclipse.swt.graphics.FontData;
36import org.eclipse.swt.layout.GridData;
37import org.eclipse.swt.layout.GridLayout;
38import org.eclipse.swt.widgets.Dialog;
39import org.eclipse.swt.widgets.Display;
40import org.eclipse.swt.widgets.Event;
41import org.eclipse.swt.widgets.Listener;
42import org.eclipse.swt.widgets.Shell;
43import org.eclipse.swt.widgets.Tree;
44import org.eclipse.swt.widgets.TreeColumn;
45import org.eclipse.swt.widgets.TreeItem;
46
47import de.ugoe.cs.autoquest.eventcore.IEventTarget;
48import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
49import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship;
50import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
51import de.ugoe.cs.autoquest.usability.UsabilitySmell;
52import de.ugoe.cs.autoquest.usability.UsabilitySmellIntensity;
53import de.ugoe.cs.autoquest.usability.UsabilityEvaluationResult;
54
55/**
56 * <p>
57 * a dialog to inspect the results of a usability evaluation
58 * TODO update comments
59 * </p>
60 *
61 * @author Patrick Harms
62 */
63public class ShowUsabilityEvaluationResultDialog extends Dialog {
64
65    /** the main shell */
66    protected Shell shell;
67
68    /** the table containing all smells */
69    private Tree smellList;
70
71    /** the description label of a selected smell */
72    private StyledText description;
73   
74    /** the tree of involved GUI elements of a specific task on the right bottom */
75    private Tree involvedTargetsTree;
76
77    /** the table containing the parents tasks of a displayed task */
78    private Tree involvedTasks;
79
80    /** the displayed usability evaluation result */
81    private UsabilityEvaluationResult usabilityEvalResult;
82   
83    /** task tree dialog to show task details */
84    private ShowTaskTreeDialog showTaskTreeDialog;
85
86    /**
87     * creates the dialog
88     */
89    public ShowUsabilityEvaluationResultDialog(Shell                     parent,
90                                               int                       style,
91                                               UsabilityEvaluationResult usabilityEvalResult,
92                                               String                    dataSetName)
93    {
94        super(parent, style);
95        setText("Usability Evaluation Result " + dataSetName);
96        this.usabilityEvalResult = usabilityEvalResult;
97    }
98
99    /**
100     * displays the dialog
101     */
102    public void open() {
103        showTaskTreeDialog = new ShowTaskTreeDialog
104            (super.getParent(), SWT.NONE, usabilityEvalResult.getTaskModel(),
105             "task details of usability smells");
106
107        createContents();
108        shell.open();
109        shell.layout();
110       
111        shell.addShellListener(new ShellAdapter() {
112            @Override
113            public void shellClosed(ShellEvent e) {
114                showTaskTreeDialog.dispose();
115            }
116        });
117       
118        Display display = getParent().getDisplay();
119        while (!shell.isDisposed()) {
120            if (!display.readAndDispatch()) {
121                display.sleep();
122            }
123        }
124    }
125
126    /**
127     * creates the two views, one on the task instances on the left, on on the task models on the
128     * right. Also adds a selection adapter to the task instances so that for a selected task
129     * instance always the respective model is presented.
130     */
131    private void createContents() {
132        shell = new Shell(getParent(), SWT.SHELL_TRIM | SWT.BORDER);
133        GraphicsDevice gd =
134            GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
135
136        shell.setSize(gd.getDisplayMode().getWidth(), gd.getDisplayMode().getHeight());
137        shell.setText(getText());
138
139        shell.setLayout(new GridLayout(1, false));
140
141        SashForm mainSashForm = new SashForm(shell, SWT.HORIZONTAL);
142        mainSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
143       
144        smellList = new Tree(mainSashForm, SWT.BORDER | SWT.SINGLE | SWT.VIRTUAL);
145        smellList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
146        smellList.setHeaderVisible(true);
147        smellList.setLinesVisible(true);
148
149        TreeColumn treeColumn = new TreeColumn(smellList, SWT.NONE);
150        treeColumn.setWidth(200);
151        treeColumn.setText("smells");
152
153        buildSmellTree();
154       
155        smellList.addSelectionListener(new SelectionAdapter() {
156            @Override
157            public void widgetSelected(SelectionEvent e) {
158                TreeItem[] selectedItems = smellList.getSelection();
159                if ((selectedItems.length == 1) &&
160                    (selectedItems[0].getData() instanceof UsabilitySmell))
161                {
162                    displaySmellDetails((UsabilitySmell) selectedItems[0].getData());
163                }
164                else {
165                    clearSmellDetails();
166                }
167            }
168        });
169
170        SashForm detailsSashForm = new SashForm(mainSashForm, SWT.VERTICAL);
171        detailsSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
172       
173        description = new StyledText(detailsSashForm, SWT.READ_ONLY | SWT.BORDER | SWT.WRAP);
174        description.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
175
176        SashForm detailsBottomSashForm = new SashForm(detailsSashForm, SWT.HORIZONTAL);
177        detailsBottomSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
178       
179        involvedTasks = VisualizationUtils.createTaskDetailsTree
180            (detailsBottomSashForm, "involved tasks", usabilityEvalResult.getTaskModel());
181       
182        VisualizationUtils.addItemSpecificContextMenu
183            (involvedTasks, ITask.class, "show details", new SelectionAdapter()
184        {
185            @Override
186            public void widgetSelected(SelectionEvent e) {
187                showTaskTreeDialog.open((ITask) involvedTasks.getSelection()[0].getData());
188            }
189        });
190       
191        VisualizationUtils.addExpansionListener(involvedTasks, new Listener() {
192            public void handleEvent(final Event event) {
193                ensureChildren((TreeItem) event.item);
194                ((TreeItem) event.item).setExpanded(true);
195            }
196        });
197       
198        involvedTargetsTree =
199            VisualizationUtils.createTargetsTree(detailsBottomSashForm, "involved GUI elements");
200       
201        VisualizationUtils.addInvolvedTargetsHighlighting(involvedTasks, involvedTargetsTree);
202       
203        detailsBottomSashForm.setWeights(new int[] { 1, 1 });
204        detailsSashForm.setWeights(new int[] { 1, 3 });
205        mainSashForm.setWeights(new int[] { 1, 3 });
206
207        //indexColumn.pack();
208        //severityColumn.pack();
209        //descriptionColumn.pack();
210        //smellList.pack();
211    }
212
213    /**
214     * convenience method for creating the display of the instances
215     */
216    private void buildSmellTree() {
217        List<UsabilitySmell> smells = usabilityEvalResult.getAllSmells();
218       
219        int[] eventCoverageQuantileGroups = { 990, 975, 950, 0, -1 };
220        int[] minEventCoverages = new int[eventCoverageQuantileGroups.length];
221        int[] maxEventCoverages = new int[eventCoverageQuantileGroups.length];
222
223        final List<Map<String, List<UsabilitySmell>>> sortedSmells =
224            new LinkedList<Map<String, List<UsabilitySmell>>>();
225       
226        for (int i = 0; i < eventCoverageQuantileGroups.length; i++) {
227            sortedSmells.add(new HashMap<String, List<UsabilitySmell>>());
228        }
229       
230        for (UsabilitySmell smell : smells) {
231            int eventCoverageQuantile = smell.getIntensity().getEventCoverageQuantile();
232           
233            for (int i = 0; i < eventCoverageQuantileGroups.length; i++) {
234                if (eventCoverageQuantile >= eventCoverageQuantileGroups[i]) {
235                    Map<String, List<UsabilitySmell>> smellMap = sortedSmells.get(i);
236                   
237                    List<UsabilitySmell> smellList = smellMap.get(smell.getBriefDescription());
238                   
239                    if (smellList == null) {
240                        smellList = new ArrayList<UsabilitySmell>();
241                        smellMap.put(smell.getBriefDescription(), smellList);
242                    }
243                   
244                    int ratio = smell.getIntensity().getRatio();
245                    int eventCoverage = smell.getIntensity().getEventCoverage();
246                    int index = 0;
247                    for (index = 0; index < smellList.size(); index++) {
248                        UsabilitySmellIntensity candidate = smellList.get(index).getIntensity();
249                        if ((ratio == candidate.getRatio()) &&
250                            (eventCoverage > candidate.getEventCoverage()))
251                        {
252                            break;
253                        }
254                        else if (ratio > candidate.getRatio()) {
255                            break;
256                        }
257                    }
258                   
259                    smellList.add(index, smell);
260                   
261                    if (minEventCoverages[i] == 0) {
262                        minEventCoverages[i] = smell.getIntensity().getEventCoverage();
263                        maxEventCoverages[i] = smell.getIntensity().getEventCoverage();
264                    }
265                    else {
266                        minEventCoverages[i] = Math.min
267                            (minEventCoverages[i], smell.getIntensity().getEventCoverage());
268                        maxEventCoverages[i] = Math.max
269                            (maxEventCoverages[i], smell.getIntensity().getEventCoverage());
270                    }
271                   
272                    break;
273                }
274            }
275        }
276       
277        if (smellList.getListeners(SWT.Expand).length == 0) {
278            smellList.addListener(SWT.Expand, new Listener() {
279               public void handleEvent(final Event event) {
280                   ensureChildren((TreeItem) event.item);
281                   ((TreeItem) event.item).setExpanded(true);
282               }
283           });
284        }
285
286        double taskPercentages = 0;
287        double taskPercentagesCoveredByPreceedingGroups = 0;
288       
289        for (int i = 0; i < eventCoverageQuantileGroups.length; i++) {
290            taskPercentages = ((1000 - eventCoverageQuantileGroups[i]) / 10.0) -
291                taskPercentagesCoveredByPreceedingGroups;
292           
293            if (eventCoverageQuantileGroups[i] > -1) {
294                createRootItem("smells for " + taskPercentages + "% of tasks covering " +
295                               minEventCoverages[i] + " to " + maxEventCoverages[i] +
296                               " recorded events", sortedSmells.get(i));
297            }
298            else {
299                createRootItem("other smells not related to specific tasks", sortedSmells.get(i));
300
301            }
302           
303            taskPercentagesCoveredByPreceedingGroups += taskPercentages;
304        }
305       
306    }
307
308    /**
309     *
310     */
311    private void createRootItem(String name, Map<String, List<UsabilitySmell>> smells) {
312        TreeItem smellItem = new TreeItem(smellList, SWT.NULL);
313       
314        int count = 0;
315        for (Map.Entry<String, List<UsabilitySmell>> entry : smells.entrySet()) {
316            count += entry.getValue().size();
317        }
318
319        smellItem.setText(name + " (" + count + " smells)");
320        smellItem.setData(smells);
321       
322        if (count > 0) {
323            // simulate a child
324            new TreeItem(smellItem, SWT.NULL);
325        }
326    }
327
328    /**
329     *
330     */
331    private void clearSmellDetails() {
332        description.setText("");
333        involvedTargetsTree.removeAll();
334        involvedTasks.removeAll();
335    }
336
337    /**
338     *
339     */
340    private void displaySmellDetails(UsabilitySmell smell) {
341        clearSmellDetails();
342       
343        FontData data = description.getFont().getFontData()[0];
344        int height = (int) (data.getHeight() * 1.5);
345        Font defaultFont = new Font
346            (description.getDisplay(), data.getName(), height, data.getStyle());
347       
348        Font boldFont = new Font
349            (description.getDisplay(), data.getName(), height, data.getStyle() | SWT.BOLD);
350       
351        for (Object fragment : smell.getDescriptionFragments()) {
352            int color;
353            Font font;
354           
355            if (fragment instanceof String) {
356                color = SWT.COLOR_BLACK;
357                font = defaultFont;
358            }
359            else {
360                color = SWT.COLOR_DARK_GREEN;
361                font = boldFont;
362            }
363           
364            int initialLength = description.getText().length();
365           
366            if (fragment instanceof Collection<?>) {
367                int counter = 1;
368                for (Object elem : ((Collection<?>) fragment)) {
369                    description.append("\n");
370                    description.append(Integer.toString(counter++));
371                    description.append(".: ");
372                    description.append(elem.toString());
373                }
374            }
375            else {
376                description.append(fragment.toString());
377            }
378           
379            StyleRange styleRange = new StyleRange
380                (initialLength, description.getText().length() - initialLength,
381                 description.getDisplay().getSystemColor(color), null);
382
383            styleRange.font = font;
384               
385            description.setStyleRange(styleRange);
386            description.append(" ");
387        }
388        description.setLeftMargin(50);
389        description.setRightMargin(50);
390        description.setTopMargin(50);
391        description.setBottomMargin(50);
392
393       
394        StyleRange styleRange = new StyleRange();
395        styleRange.font = new Font(description.getDisplay(), "Courier", 12, SWT.NORMAL);
396        description.setStyleRange(styleRange);
397       
398        List<ITask> involvedTaskList = getInvolvedTasks(smell);
399        for (ITask involvedTask : involvedTaskList) {
400            VisualizationUtils.createTreeItemFor
401                (involvedTask, involvedTasks, usabilityEvalResult.getTaskModel(), true);
402        }
403       
404        List<IEventTarget> involvedTargets = getInvolvedTargets(smell);
405        if (involvedTargets.size() <= 0) {
406            for (ITask involvedTask : involvedTaskList) {
407                VisualizationUtils.getInvolvedTargets(involvedTask, involvedTargets);
408            }
409        }
410       
411        VisualizationUtils.addInvolvedTargets(involvedTargetsTree, involvedTargets);
412       
413        int weightLeft = involvedTaskList.size() == 0 ? 1 :
414            Math.min(4, Math.max(3, involvedTaskList.size()));
415        int weightRight = involvedTargets.size() == 0 ? 1 :
416            Math.min(3, Math.max(1, involvedTargets.size()));
417        ((SashForm) involvedTasks.getParent()).setWeights(new int[] { weightLeft, weightRight });
418       
419        VisualizationUtils.expandAll(involvedTasks, true);
420        VisualizationUtils.updateColumnWidths(involvedTasks);
421    }
422   
423    /**
424     *
425     */
426    private void ensureChildren(TreeItem parent) {
427        if ((parent.getItemCount() == 0) || (parent.getItems()[0].getData() != null)) {
428            return;
429        }
430       
431        for (int i = 0; i < parent.getItems().length; i++) {
432            parent.getItems()[i].dispose();
433        }
434       
435        if (parent.getData() instanceof Map<?, ?>) {
436            @SuppressWarnings("unchecked")
437            Map<String, List<UsabilitySmell>> map =
438                (Map<String, List<UsabilitySmell>>) parent.getData();
439           
440            for (Map.Entry<String, List<UsabilitySmell>> entry : map.entrySet()) {
441                TreeItem child = new TreeItem(parent, SWT.NULL);       
442                child.setText(entry.getKey() + " (" + entry.getValue().size() + " smells)");
443                child.setData(entry);
444               
445                if (entry.getValue().size() > 0) {
446                    // simulate child
447                    new TreeItem(child, SWT.NULL);
448                }
449            }
450        }
451        else if (parent.getData() instanceof Map.Entry<?, ?>) {
452            @SuppressWarnings("unchecked")
453            Map.Entry<String, List<UsabilitySmell>> entry =
454                (Map.Entry<String, List<UsabilitySmell>>) parent.getData();
455           
456            int count = 0;
457            for (UsabilitySmell smell : entry.getValue()) {
458                TreeItem child = new TreeItem(parent, SWT.NULL);       
459                child.setData(smell);
460                child.setText(++count + ": ratio = " + smell.getIntensity().getRatio() +
461                              ", covered events = " + smell.getIntensity().getEventCoverage());
462            }
463        }
464        else if (parent.getData() instanceof ITask) {
465            ITask task = (ITask) parent.getData();
466
467            if (task instanceof IStructuringTemporalRelationship) {
468                for (ITask subTask : ((IStructuringTemporalRelationship) task).getChildren()) {
469                    VisualizationUtils.createTreeItemFor
470                        (subTask, parent, usabilityEvalResult.getTaskModel(), true);
471                }
472            }
473            else if (task instanceof IMarkingTemporalRelationship) {
474                VisualizationUtils.createTreeItemFor
475                    (((IMarkingTemporalRelationship) task).getMarkedTask(), parent,
476                     usabilityEvalResult.getTaskModel(), true);
477            }
478        }
479    }
480   
481    /**
482     *
483     */
484    private List<ITask> getInvolvedTasks(UsabilitySmell smell) {
485        List<Object> fragments = smell.getDescriptionFragments();
486        List<ITask> involvedTasks = new ArrayList<ITask>();
487       
488        for (Object fragment : fragments) {
489            if (fragment instanceof ITask) {
490                involvedTasks.add((ITask) fragment);
491            }
492        }
493       
494        return involvedTasks;
495    }
496
497    /**
498     *
499     */
500    private List<IEventTarget> getInvolvedTargets(UsabilitySmell smell) {
501        List<Object> fragments = smell.getDescriptionFragments();
502        List<IEventTarget> involvedTargets = new ArrayList<IEventTarget>();
503       
504        for (Object fragment : fragments) {
505            if (fragment instanceof IEventTarget) {
506                involvedTargets.add((IEventTarget) fragment);
507            }
508            else if (fragment instanceof Collection<?>) {
509                for (Object elem : (Collection<?>) fragment) {
510                    if (elem instanceof IEventTarget) {
511                        involvedTargets.add((IEventTarget) elem);
512                    }
513                }
514            }
515        }
516       
517        return involvedTargets;
518    }
519}
Note: See TracBrowser for help on using the repository browser.