// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.ui.swt; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Dialog; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import de.ugoe.cs.autoquest.eventcore.IEventTarget; import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship; import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; import de.ugoe.cs.autoquest.usability.UsabilityDefect; import de.ugoe.cs.autoquest.usability.UsabilityDefectSeverity; import de.ugoe.cs.autoquest.usability.UsabilityEvaluationResult; /** *

* a dialog to inspect the results of a usability evaluation *

* * @author Patrick Harms */ public class ShowUsabilityEvaluationResultDialog extends Dialog { /** the main shell */ protected Shell shell; /** the table containing all defects */ private Tree defectList; /** the description label of a selected defect */ private StyledText description; /** the tree of involved GUI elements of a specific task on the right bottom */ private Tree involvedTargetsTree; /** the table containing the parents tasks of a displayed task */ private Tree involvedTasks; /** the displayed task model */ private UsabilityEvaluationResult usabilityEvalResult; /** task tree dialog to show task details */ private ShowTaskTreeDialog showTaskTreeDialog; /** * creates the dialog */ public ShowUsabilityEvaluationResultDialog(Shell parent, int style, UsabilityEvaluationResult usabilityEvalResult, String dataSetName) { super(parent, style); setText("Usability Evaluation Result " + dataSetName); this.usabilityEvalResult = usabilityEvalResult; } /** * displays the dialog */ public void open() { showTaskTreeDialog = new ShowTaskTreeDialog (super.getParent(), SWT.NONE, usabilityEvalResult.getTaskModel(), "task details of usability defects"); createContents(); shell.open(); shell.layout(); shell.addShellListener(new ShellAdapter() { @Override public void shellClosed(ShellEvent e) { showTaskTreeDialog.dispose(); } }); Display display = getParent().getDisplay(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } /** * creates the two views, one on the task instances on the left, on on the task models on the * right. Also adds a selection adapter to the task instances so that for a selected task * instance always the respective model is presented. */ private void createContents() { shell = new Shell(getParent(), SWT.SHELL_TRIM | SWT.BORDER); GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); shell.setSize(gd.getDisplayMode().getWidth(), gd.getDisplayMode().getHeight()); shell.setText(getText()); shell.setLayout(new GridLayout(1, false)); SashForm mainSashForm = new SashForm(shell, SWT.HORIZONTAL); mainSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); defectList = new Tree(mainSashForm, SWT.BORDER | SWT.SINGLE | SWT.VIRTUAL); defectList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); defectList.setHeaderVisible(true); defectList.setLinesVisible(true); TreeColumn treeColumn = new TreeColumn(defectList, SWT.NONE); treeColumn.setWidth(200); treeColumn.setText("defects"); buildDefectTree(); defectList.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { TreeItem[] selectedItems = defectList.getSelection(); if ((selectedItems.length == 1) && (selectedItems[0].getData() instanceof UsabilityDefect)) { displayDefectDetails((UsabilityDefect) selectedItems[0].getData()); } else { clearDefectDetails(); } } }); SashForm detailsSashForm = new SashForm(mainSashForm, SWT.VERTICAL); detailsSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); description = new StyledText(detailsSashForm, SWT.READ_ONLY | SWT.BORDER | SWT.WRAP); description.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); SashForm detailsBottomSashForm = new SashForm(detailsSashForm, SWT.HORIZONTAL); detailsBottomSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); involvedTasks = VisualizationUtils.createTaskDetailsTree (detailsBottomSashForm, "involved tasks", usabilityEvalResult.getTaskModel()); VisualizationUtils.addItemSpecificContextMenu (involvedTasks, ITask.class, "show details", new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { showTaskTreeDialog.open((ITask) involvedTasks.getSelection()[0].getData()); } }); VisualizationUtils.addExpansionListener(involvedTasks, new Listener() { public void handleEvent(final Event event) { ensureChildren((TreeItem) event.item); ((TreeItem) event.item).setExpanded(true); } }); involvedTargetsTree = VisualizationUtils.createTargetsTree(detailsBottomSashForm, "involved GUI elements"); VisualizationUtils.addInvolvedTargetsHighlighting(involvedTasks, involvedTargetsTree); detailsBottomSashForm.setWeights(new int[] { 1, 1 }); detailsSashForm.setWeights(new int[] { 1, 3 }); mainSashForm.setWeights(new int[] { 1, 3 }); //indexColumn.pack(); //severityColumn.pack(); //descriptionColumn.pack(); //defectList.pack(); } /** * convenience method for creating the display of the instances */ private void buildDefectTree() { List defects = usabilityEvalResult.getAllDefects(); final Map>> sortedDefects = new HashMap>>(); sortedDefects.put(UsabilityDefectSeverity.HIGH, new HashMap>()); sortedDefects.put(UsabilityDefectSeverity.MEDIUM, new HashMap>()); sortedDefects.put(UsabilityDefectSeverity.LOW, new HashMap>()); sortedDefects.put(UsabilityDefectSeverity.INFO, new HashMap>()); for (UsabilityDefect defect : defects) { Map> defectMap = sortedDefects.get(defect.getSeverity()); List defectList = defectMap.get(defect.getBriefDescription()); if (defectList == null) { defectList = new ArrayList(); defectMap.put(defect.getBriefDescription(), defectList); } defectList.add(defect); } if (defectList.getListeners(SWT.Expand).length == 0) { defectList.addListener(SWT.Expand, new Listener() { public void handleEvent(final Event event) { ensureChildren((TreeItem) event.item); ((TreeItem) event.item).setExpanded(true); } }); } createRootItem("high", sortedDefects.get(UsabilityDefectSeverity.HIGH)); createRootItem("medium", sortedDefects.get(UsabilityDefectSeverity.MEDIUM)); createRootItem("low", sortedDefects.get(UsabilityDefectSeverity.LOW)); createRootItem("info", sortedDefects.get(UsabilityDefectSeverity.INFO)); } /** * */ private void createRootItem(String name, Map> defects) { TreeItem defectItem = new TreeItem(defectList, SWT.NULL); int count = 0; for (Map.Entry> entry : defects.entrySet()) { count += entry.getValue().size(); } defectItem.setText(name + " severity (" + count + " defects)"); defectItem.setData(defects); if (count > 0) { // simulate a child new TreeItem(defectItem, SWT.NULL); } } /** * */ private void clearDefectDetails() { description.setText(""); involvedTargetsTree.removeAll(); involvedTasks.removeAll(); } /** * */ private void displayDefectDetails(UsabilityDefect defect) { clearDefectDetails(); FontData data = description.getFont().getFontData()[0]; int height = (int) (data.getHeight() * 1.5); Font defaultFont = new Font (description.getDisplay(), data.getName(), height, data.getStyle()); Font boldFont = new Font (description.getDisplay(), data.getName(), height, data.getStyle() | SWT.BOLD); for (Object fragment : defect.getDescriptionFragments()) { int color; Font font; if (fragment instanceof String) { color = SWT.COLOR_BLACK; font = defaultFont; } else { color = SWT.COLOR_DARK_GREEN; font = boldFont; } StyleRange styleRange = new StyleRange (description.getText().length(), fragment.toString().length(), description.getDisplay().getSystemColor(color), null); styleRange.font = font; if (fragment instanceof Collection) { int counter = 1; for (Object elem : ((Collection) fragment)) { description.append("\n"); description.append(Integer.toString(counter++)); description.append(".: "); description.append(elem.toString()); } } else { description.append(fragment.toString()); } description.setStyleRange(styleRange); description.append(" "); } description.setLeftMargin(50); description.setRightMargin(50); description.setTopMargin(50); description.setBottomMargin(50); StyleRange styleRange = new StyleRange(); styleRange.font = new Font(description.getDisplay(), "Courier", 12, SWT.NORMAL); description.setStyleRange(styleRange); List involvedTaskList = getInvolvedTasks(defect); for (ITask involvedTask : involvedTaskList) { VisualizationUtils.createTreeItemFor (involvedTask, involvedTasks, usabilityEvalResult.getTaskModel(), true); } List involvedTargets = getInvolvedTargets(defect); if (involvedTargets.size() <= 0) { for (ITask involvedTask : involvedTaskList) { VisualizationUtils.getInvolvedTargets(involvedTask, involvedTargets); } } VisualizationUtils.addInvolvedTargets(involvedTargetsTree, involvedTargets); int weightLeft = involvedTaskList.size() == 0 ? 1 : Math.min(4, Math.max(3, involvedTaskList.size())); int weightRight = involvedTargets.size() == 0 ? 1 : Math.min(3, Math.max(1, involvedTargets.size())); ((SashForm) involvedTasks.getParent()).setWeights(new int[] { weightLeft, weightRight }); VisualizationUtils.expandAll(involvedTasks, true); VisualizationUtils.updateColumnWidths(involvedTasks); } /** * */ private void ensureChildren(TreeItem parent) { if ((parent.getItemCount() == 0) || (parent.getItems()[0].getData() != null)) { return; } for (int i = 0; i < parent.getItems().length; i++) { parent.getItems()[i].dispose(); } if (parent.getData() instanceof Map) { @SuppressWarnings("unchecked") Map> map = (Map>) parent.getData(); for (Map.Entry> entry : map.entrySet()) { TreeItem child = new TreeItem(parent, SWT.NULL); child.setText(entry.getKey() + " (" + entry.getValue().size() + " defects)"); child.setData(entry); if (entry.getValue().size() > 0) { // simulate child new TreeItem(child, SWT.NULL); } } } else if (parent.getData() instanceof Map.Entry) { @SuppressWarnings("unchecked") Map.Entry> entry = (Map.Entry>) parent.getData(); int count = 0; for (UsabilityDefect defect : entry.getValue()) { TreeItem child = new TreeItem(parent, SWT.NULL); child.setData(defect); child.setText("defect " + ++count); } } else if (parent.getData() instanceof ITask) { ITask task = (ITask) parent.getData(); if (task instanceof IStructuringTemporalRelationship) { for (ITask subTask : ((IStructuringTemporalRelationship) task).getChildren()) { VisualizationUtils.createTreeItemFor (subTask, parent, usabilityEvalResult.getTaskModel(), true); } } else if (task instanceof IMarkingTemporalRelationship) { VisualizationUtils.createTreeItemFor (((IMarkingTemporalRelationship) task).getMarkedTask(), parent, usabilityEvalResult.getTaskModel(), true); } } } /** * */ private List getInvolvedTasks(UsabilityDefect defect) { List fragments = defect.getDescriptionFragments(); List involvedTasks = new ArrayList(); for (Object fragment : fragments) { if (fragment instanceof ITask) { involvedTasks.add((ITask) fragment); } } return involvedTasks; } /** * */ private List getInvolvedTargets(UsabilityDefect defect) { List fragments = defect.getDescriptionFragments(); List involvedTargets = new ArrayList(); for (Object fragment : fragments) { if (fragment instanceof IEventTarget) { involvedTargets.add((IEventTarget) fragment); } else if (fragment instanceof Collection) { for (Object elem : (Collection) fragment) { if (elem instanceof IEventTarget) { involvedTargets.add((IEventTarget) elem); } } } } return involvedTargets; } }