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

Last change on this file since 1424 was 1424, checked in by pharms, 10 years ago
  • improved the presentation of task models
File size: 24.3 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.Collection;
20import java.util.Collections;
21import java.util.Comparator;
22import java.util.LinkedList;
23import java.util.List;
24
25import org.eclipse.swt.SWT;
26import org.eclipse.swt.custom.SashForm;
27import org.eclipse.swt.events.SelectionAdapter;
28import org.eclipse.swt.events.SelectionEvent;
29import org.eclipse.swt.events.ShellAdapter;
30import org.eclipse.swt.events.ShellEvent;
31import org.eclipse.swt.events.ShellListener;
32import org.eclipse.swt.layout.GridData;
33import org.eclipse.swt.layout.GridLayout;
34import org.eclipse.swt.widgets.Button;
35import org.eclipse.swt.widgets.Composite;
36import org.eclipse.swt.widgets.Dialog;
37import org.eclipse.swt.widgets.Display;
38import org.eclipse.swt.widgets.Event;
39import org.eclipse.swt.widgets.Label;
40import org.eclipse.swt.widgets.Listener;
41import org.eclipse.swt.widgets.Shell;
42import org.eclipse.swt.widgets.TabFolder;
43import org.eclipse.swt.widgets.TabItem;
44import org.eclipse.swt.widgets.Tree;
45import org.eclipse.swt.widgets.TreeColumn;
46import org.eclipse.swt.widgets.TreeItem;
47
48import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
49import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
50import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional;
51import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
52import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
53import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
54import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
55import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship;
56import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
57import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
58import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList;
59import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
60import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
61
62/**
63 * <p>
64 * a dialog to inspect the tasks and task instances of a task model
65 * </p>
66 *
67 * @author Patrick Harms
68 */
69public class ShowTaskTreeDialog extends Dialog {
70
71    /** the main shell */
72    private Shell shell;
73   
74    /** the listener for the main shell to prevent disposing required */
75    private ShellListener shellListener;
76   
77    /** the tab folder containing the instance tree as well as the model tree */
78    private TabFolder tabFolder;
79
80    /** the tree of task instances on the left */
81    private Tree instanceTree;
82   
83    /** the tree of tasks on the left */
84    private Tree modelTree;
85   
86    /** the tree of a specific task on the right */
87    private Tree taskDetailsTree;
88
89    /** the tree of execution variants of a specific task on the right */
90    private Tree executionVariantsTree;
91
92    /** the tree of involved GUI elements of a specific task on the right bottom */
93    private Tree involvedGUIElementsTree;
94
95    /** the table containing the parents tasks of a displayed task */
96    private Tree parentTasks;
97
98    /** the displayed task model */
99    private ITaskModel taskModel;
100   
101    /** default expansion listener */
102    private Listener defaultExpansionListener = new Listener() {
103        public void handleEvent(final Event event) {
104            ensureChildren((TreeItem) event.item);
105            ((TreeItem) event.item).setExpanded(true);
106        }
107    };
108
109    /**
110     * creates the dialog
111     */
112    public ShowTaskTreeDialog(Shell parent, int style, ITaskModel taskModel, String taskTreeName) {
113        super(parent, style);
114        setText("Task Model " + taskTreeName);
115        this.taskModel = taskModel;
116    }
117
118    /**
119     * displays the dialog
120     * @param task
121     */
122    public void open() {
123        open(null);
124    }
125
126    /**
127     * displays the dialog with a specific task opened
128     * @param task
129     */
130    public void open(ITask task) {
131        if (shell == null) {
132            createContents();
133            shell.open();
134            shell.layout();
135
136            VisualizationUtils.updateColumnWidths(taskDetailsTree);
137        }
138        else {
139            shell.setVisible(true);
140        }
141       
142        if (task != null) {
143            shellListener = new ShellAdapter() {
144                @Override
145                public void shellClosed(ShellEvent e) {
146                    e.doit = false;
147                    shell.setVisible(false);
148                }
149            };
150           
151            shell.addShellListener(shellListener);
152        }
153
154        if (task != null) {
155            navigateTo(task);
156        }
157       
158        Display display = getParent().getDisplay();
159        while (!shell.isDisposed() && shell.isVisible()) {
160            if (!display.readAndDispatch()) {
161                display.sleep();
162            }
163        }
164       
165        if (task == null) {
166            dispose();
167        }
168    }
169
170    /**
171     * disposes the dialog if it is not used anymore
172     */
173    public void dispose() {
174        if ((shell != null) && (!shell.isDisposed())) {
175            if (shellListener != null) {
176                shell.removeShellListener(shellListener);
177            }
178           
179            shell.dispose();
180        }
181    }
182
183    /**
184     * creates the two views, one on the task instances on the left, on on the task models on the
185     * right. Also adds a selection adapter to the task instances so that for a selected task
186     * instance always the respective model is presented.
187     */
188    private void createContents() {
189        shell = new Shell(getParent(), SWT.SHELL_TRIM | SWT.BORDER);
190
191        GraphicsDevice gd =
192            GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
193       
194        shell.setSize(gd.getDisplayMode().getWidth(), gd.getDisplayMode().getHeight());
195        shell.setText(getText());
196
197        shell.setLayout(new GridLayout(4, false));
198       
199        SashForm mainSashForm = new SashForm(shell, SWT.HORIZONTAL);
200        mainSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));
201       
202        createSessionsAndTasksTabFolder(mainSashForm);
203        createTaskDetailsView(mainSashForm);
204
205        mainSashForm.setWeights(new int[] { 1, 3 });
206
207        Button btnExpandAll = new Button(shell, SWT.NONE);
208        btnExpandAll.addSelectionListener(new SelectionAdapter() {
209            @Override
210            public void widgetSelected(SelectionEvent e) {
211                if (tabFolder.getSelectionIndex() == 0) {
212                    VisualizationUtils.expandAll(instanceTree, true);
213                }
214                else {
215                    VisualizationUtils.expandAll(modelTree, true);
216                }
217            }
218        });
219        btnExpandAll.setText("Expand all");
220
221        Button btnCollapseAll = new Button(shell, SWT.NONE);
222        btnCollapseAll.addSelectionListener(new SelectionAdapter() {
223            @Override
224            public void widgetSelected(SelectionEvent e) {
225                if (tabFolder.getSelectionIndex() == 0) {
226                    VisualizationUtils.expandAll(instanceTree, false);
227                }
228                else {
229                    VisualizationUtils.expandAll(modelTree, false);
230                }
231            }
232        });
233        btnCollapseAll.setText("Collapse all");
234       
235        new Label(shell, SWT.NONE);
236        new Label(shell, SWT.NONE);
237    }
238
239    /**
240     *
241     */
242    private void createSessionsAndTasksTabFolder(SashForm mainSashForm) {
243        tabFolder = new TabFolder(mainSashForm, SWT.NONE);
244        tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
245        tabFolder.addSelectionListener(new SelectionAdapter() {
246            @Override
247            public void widgetSelected(SelectionEvent e) {
248                VisualizationUtils.updateColumnWidths(modelTree);
249            }
250        });
251       
252        TabItem instanceTreeTab = new TabItem(tabFolder, SWT.NONE);
253        instanceTreeTab.setText("Task Instances");
254
255        instanceTree = new Tree(tabFolder, SWT.BORDER | SWT.SINGLE | SWT.VIRTUAL);
256        instanceTree.addSelectionListener(new SelectionAdapter() {
257            @Override
258            public void widgetSelected(SelectionEvent e) {
259                TreeItem[] selectedItems = instanceTree.getSelection();
260                if ((selectedItems.length == 1) &&
261                    (selectedItems[0].getData() instanceof ITaskInstance))
262                {
263                    displayTaskDetails(((ITaskInstance) selectedItems[0].getData()).getTask());
264                }
265                else {
266                    clearTaskDetails();
267                }
268            }
269        });
270
271        VisualizationUtils.addItemSpecificContextMenu
272            (instanceTree, ITaskInstance.class, "show in task list", new SelectionAdapter()
273        {
274            @Override
275            public void widgetSelected(SelectionEvent e) {
276                navigateTo(((ITaskInstance) instanceTree.getSelection()[0].getData()).getTask());
277            }
278        });
279
280        buildInstanceTree();
281        instanceTreeTab.setControl(instanceTree);
282
283        TabItem modelTreeTab = new TabItem(tabFolder, SWT.NONE);
284        modelTreeTab.setText("Tasks");
285       
286        modelTree =
287            VisualizationUtils.createTaskDetailsTree(tabFolder, "tasks in model", taskModel);
288       
289        // show task details if requested
290        modelTree.addSelectionListener(new SelectionAdapter() {
291            @Override
292            public void widgetSelected(SelectionEvent e) {
293                TreeItem[] selectedItems = modelTree.getSelection();
294                if ((selectedItems.length == 1) && (selectedItems[0].getData() instanceof ITask)) {
295                    displayTaskDetails((ITask) selectedItems[0].getData());
296                }
297                else {
298                    clearTaskDetails();
299                }
300            }
301        });
302       
303        buildModelTree(taskModel);
304       
305        modelTreeTab.setControl(modelTree);
306    }
307
308    /**
309     *
310     */
311    private void createTaskDetailsView(SashForm mainSashForm) {
312        Composite detailsComposite = new Composite(mainSashForm, SWT.NO_BACKGROUND);
313        detailsComposite.setLayout(new GridLayout(1, false));
314        detailsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
315       
316        new Label(detailsComposite, SWT.NONE).setText("Task Details:");
317       
318        SashForm detailsSashForm = new SashForm(detailsComposite, SWT.VERTICAL);
319        detailsSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
320       
321        SashForm detailsTopSashForm = new SashForm(detailsSashForm, SWT.HORIZONTAL);
322        detailsTopSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
323       
324        taskDetailsTree =
325            VisualizationUtils.createTaskDetailsTree(detailsTopSashForm, "task details", taskModel);
326       
327        VisualizationUtils.addExpansionListener(taskDetailsTree, defaultExpansionListener);
328       
329        VisualizationUtils.addItemSpecificContextMenu(taskDetailsTree, ITask.class,
330                                                      "show in task list", new SelectionAdapter()
331        {
332            @Override
333            public void widgetSelected(SelectionEvent e) {
334                navigateTo((ITask) taskDetailsTree.getSelection()[0].getData());
335            }
336        });
337       
338        executionVariantsTree = new Tree(detailsTopSashForm, SWT.BORDER | SWT.SINGLE | SWT.WRAP);
339        executionVariantsTree.setHeaderVisible(true);
340       
341        TreeColumn taskColumn = new TreeColumn(executionVariantsTree, SWT.NONE);
342        taskColumn.setText("instance variants");
343        taskColumn.setAlignment(SWT.LEFT);
344
345        // load the correct children on expansion
346        VisualizationUtils.addExpansionListener(executionVariantsTree, defaultExpansionListener);
347       
348        detailsTopSashForm.setWeights(new int[] { 3, 2 });
349
350        SashForm detailsBottomSashForm = new SashForm(detailsSashForm, SWT.HORIZONTAL);
351        detailsBottomSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
352       
353        parentTasks = VisualizationUtils.createTaskDetailsTree
354            (detailsBottomSashForm, "parent tasks", taskModel);
355       
356        VisualizationUtils.addItemSpecificContextMenu(parentTasks, ITask.class,
357                                                      "show in task list", new SelectionAdapter()
358        {
359            @Override
360            public void widgetSelected(SelectionEvent e) {
361                navigateTo((ITask) parentTasks.getSelection()[0].getData());
362            }
363        });
364       
365        involvedGUIElementsTree =
366            VisualizationUtils.createGUIElementsTree(detailsBottomSashForm, "involved GUI elements");
367       
368        detailsBottomSashForm.setWeights(new int[] { 2, 3 });
369        detailsSashForm.setWeights(new int[] { 1, 1 });
370    }
371
372    /**
373     * convenience method for creating the display of the instances
374     */
375    private void buildInstanceTree() {
376        List<IUserSession> sessions = taskModel.getUserSessions();
377
378        // load the correct children on expansion
379        VisualizationUtils.addExpansionListener(instanceTree, defaultExpansionListener);
380
381        TreeItem root = new TreeItem(instanceTree, SWT.NULL);
382        root.setText(sessions.size() + " sessions");
383        root.setData(taskModel);
384       
385        for (IUserSession session : sessions) {
386            buildInstanceTree(root, session);
387        }
388       
389        root.setExpanded(true);
390    }
391
392    /**
393     * convenience method for creating the display of the instances
394     */
395    private void buildInstanceTree(TreeItem currentParent, IUserSession session) {
396        TreeItem item = new TreeItem(currentParent, SWT.NULL);
397        item.setText(session.toString());
398        item.setData(session);
399       
400        // simulate a child
401        new TreeItem(item, SWT.NULL);
402    }
403
404    /**
405     * convenience method for creating the display of the task model
406     */
407    private void buildModelTree(ITaskModel taskModel) {
408        Collection<ITask> allTasks = taskModel.getTasks();
409       
410        List<ITask> sequences = new LinkedList<ITask>();
411        List<ITask> iterations = new LinkedList<ITask>();
412        List<ITask> selections = new LinkedList<ITask>();
413        List<ITask> optionals = new LinkedList<ITask>();
414        List<ITask> others = new LinkedList<ITask>();
415       
416        TreeItem root = new TreeItem(modelTree, SWT.NULL);
417        root.setText(allTasks.size() + " tasks in model");
418        root.setData(taskModel);
419
420        createSortedTaskLists(allTasks, sequences, iterations, selections, optionals, others);
421       
422        //allTasks = createSortedTaskList(allTasks);
423       
424        createModelTreeItemFor(sequences, sequences.size() + " Sequences", root);
425        createModelTreeItemFor(iterations, iterations.size() + " Iterations", root);
426        createModelTreeItemFor(selections, selections.size() + " Selections", root);
427        createModelTreeItemFor(optionals, optionals.size() + " Optionals", root);
428        createModelTreeItemFor(others, others.size() + " other Tasks", root);
429       
430        root.setExpanded(true);
431    }
432
433    /**
434     *
435     */
436    private void createSortedTaskLists(Collection<ITask> allTasks,
437                                       List<ITask>       sequences,
438                                       List<ITask>       iterations,
439                                       List<ITask>       selections,
440                                       List<ITask>       optionals,
441                                       List<ITask>       others)
442    {
443        List<ITask> toAdd;
444       
445        for (ITask task : allTasks) {
446            if (task instanceof ISequence) {
447                toAdd = sequences;
448            }
449            else if (task instanceof IIteration) {
450                toAdd = iterations;
451            }
452            else if (task instanceof ISelection) {
453                toAdd = selections;
454            }
455            else if (task instanceof IOptional) {
456                toAdd = optionals;
457            }
458            else {
459                toAdd = others;
460            }
461           
462            int taskCount = task.getInstances().size();
463            int start = 0;
464            int end = toAdd.size();
465            int center = 0;
466            int centerCount;
467           
468            while (start != end) {
469                center = start + ((end - start) / 2);
470               
471                if ((center != start) || (center != end)) {
472                    centerCount = toAdd.get(center).getInstances().size();
473               
474                    if (centerCount > taskCount) {
475                        start = Math.max(center, start + 1);
476                    }
477                    else if (centerCount < taskCount) {
478                        end = Math.min(center, end - 1);
479                    }
480                    else {
481                        // add the event directly where the center is, as the count of the center
482                        // and the new task are equal
483                        end = center;
484                        start = end;
485                        break;
486                    }
487                }
488                else {
489                    // add the event to the position denoted by the add index
490                    break;
491                }
492            }
493           
494            toAdd.add(start, task);
495        }
496    }
497
498    /**
499     *
500     */
501    private void clearTaskDetails() {
502        taskDetailsTree.removeAll();
503        executionVariantsTree.removeAll();
504        involvedGUIElementsTree.removeAll();
505        parentTasks.removeAll();
506    }
507
508    /**
509     *
510     */
511    private void displayTaskDetails(ITask task) {
512        clearTaskDetails();
513       
514        VisualizationUtils.createTreeItemFor(task, taskDetailsTree, taskModel, true);
515        VisualizationUtils.expandAll(taskDetailsTree, true);
516       
517        // do it twice. Otherwise, it doesn't work
518        VisualizationUtils.updateColumnWidths(taskDetailsTree);
519       
520        Collection<Collection<ITaskInstance>> executionVariants = task.getExecutionVariants();
521        List<Collection<ITaskInstance>> sortedExecutionVariants =
522            new LinkedList<Collection<ITaskInstance>>(executionVariants);
523       
524        Collections.sort(sortedExecutionVariants, new Comparator<Collection<ITaskInstance>>() {
525            @Override
526            public int compare(Collection<ITaskInstance> list1, Collection<ITaskInstance> list2) {
527                return list2.size() - list1.size();
528            }
529        });
530       
531        int counter = 1;
532        for (Collection<ITaskInstance> variant : sortedExecutionVariants) {
533            TreeItem item = new TreeItem(executionVariantsTree, SWT.NULL);
534            if (variant.size() > 1) {
535                item.setText("variant " + counter++ + " (executed " + variant.size() + " times)");
536            }
537            else {
538                item.setText("variant " + counter++ + " (executed once)");
539            }
540            item.setData(variant);
541           
542            createTreeItemFor(variant.iterator().next(), item);
543        }
544
545        VisualizationUtils.expandAll(executionVariantsTree, true);
546        VisualizationUtils.updateColumnWidths(executionVariantsTree);
547       
548        addParentTasks(task);
549        VisualizationUtils.updateColumnWidths(parentTasks);
550       
551        VisualizationUtils.addInvolvedTargets(involvedGUIElementsTree, task);
552    }
553
554    /**
555     *
556     */
557    private void addParentTasks(ITask task) {
558        for (ITask candidate : taskModel.getTasks()) {
559            if (((candidate instanceof IStructuringTemporalRelationship) &&
560                 (((IStructuringTemporalRelationship) candidate).getChildren().contains(task))) ||
561                ((candidate instanceof IMarkingTemporalRelationship) &&
562                 (((IMarkingTemporalRelationship) candidate).getMarkedTask().equals(task))))
563            {
564                VisualizationUtils.createTreeItemFor(candidate, parentTasks, taskModel, false);
565            }
566        }
567    }
568
569    /**
570     *
571     */
572    private void navigateTo(ITask task) {
573        tabFolder.setSelection(1);
574       
575        OUTER:
576        for (TreeItem sublist : modelTree.getItem(0).getItems()) {
577            for (TreeItem taskItem : sublist.getItems()) {
578                if (task.equals(taskItem.getData())) {
579                    modelTree.setSelection(taskItem);
580                    sublist.setExpanded(true);
581                    VisualizationUtils.updateColumnWidths(modelTree);
582                    break OUTER;
583                }
584            }
585        }
586       
587        displayTaskDetails(task);
588    }
589   
590    /**
591     * ensures, that the children of a specific node are loaded
592     */
593    private void ensureChildren(TreeItem parent) {
594        TreeItem[] items = parent.getItems();
595        if ((items == null) || (items.length == 0) || (items[0].getData() == null)) {
596            if (items != null) {
597                for (int i = 0; i < items.length; i++) {
598                    items[i].dispose();
599                }
600            }
601
602            if (parent.getData() instanceof ITask) {
603                ITask task = (ITask) parent.getData();
604
605                if (task instanceof IStructuringTemporalRelationship) {
606                    for (ITask subTask : ((IStructuringTemporalRelationship) task).getChildren()) {
607                        VisualizationUtils.createTreeItemFor(subTask, parent, taskModel, true);
608                    }
609                }
610                else if (task instanceof IMarkingTemporalRelationship) {
611                    VisualizationUtils.createTreeItemFor
612                        (((IMarkingTemporalRelationship) task).getMarkedTask(), parent,
613                         taskModel, true);
614                }
615            }
616            else if (parent.getData() instanceof List<?>) {
617                @SuppressWarnings("unchecked")
618                List<ITask> tasks = (List<ITask>) parent.getData();
619                for (ITask task : tasks) {
620                    VisualizationUtils.createTreeItemFor(task, parent, taskModel, false);
621                }
622            }
623            else if (parent.getData() instanceof ITaskInstanceList) {
624                for (ITaskInstance subInstance : (ITaskInstanceList) parent.getData()) {
625                    createTreeItemFor(subInstance, parent);
626                }
627            }
628            else if (parent.getData() instanceof ITaskInstance) {
629                ITaskInstance instance = (ITaskInstance) parent.getData();
630
631                if (instance instanceof ISelectionInstance) {
632                    if (((ISelectionInstance) instance).getChild() != null) {
633                        createTreeItemFor(((ISelectionInstance) instance).getChild(), parent);
634                    }
635                }
636                else if (instance instanceof IOptionalInstance) {
637                    if (((IOptionalInstance) instance).getChild() != null) {
638                        createTreeItemFor(((IOptionalInstance) instance).getChild(), parent);
639                    }
640                }
641            }
642        }
643    }
644
645    /**
646     *
647     */
648    private void createModelTreeItemFor(List<ITask> taskList, String name, TreeItem parent) {
649        TreeItem item = new TreeItem(parent, SWT.NULL);
650        item.setText(name);
651        item.setData(taskList);
652       
653        // simulate a child
654        if (taskList.size() > 0) {
655            for (ITask task : taskList) {
656                VisualizationUtils.createTreeItemFor(task, item, taskModel, false);
657            }
658        }
659    }
660
661    /**
662     * convenience method to create a tree item for a task
663     */
664    private void createTreeItemFor(ITaskInstance taskInstance,
665                                   TreeItem      parent)
666    {
667        TreeItem item = new TreeItem(parent, SWT.NULL);
668        item.setText(taskInstance.toString());
669        item.setData(taskInstance);
670       
671        // simulate a child
672        if ((taskInstance instanceof ITaskInstanceList) ||
673            (taskInstance instanceof ISelectionInstance) ||
674            (taskInstance instanceof IOptionalInstance))
675        {
676            new TreeItem(item, SWT.NULL);
677        }
678    }
679}
Note: See TracBrowser for help on using the repository browser.