| /******************************************************************************* |
| * Copyright (c) 2009, 2016 Xored Software Inc and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Xored Software Inc - initial API and implementation and/or initial documentation |
| *******************************************************************************/ |
| package org.eclipse.rcptt.verifications.tree.ui; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.core.databinding.Binding; |
| import org.eclipse.core.databinding.observable.value.AbstractObservableValue; |
| import org.eclipse.emf.common.util.EMap; |
| import org.eclipse.emf.databinding.EMFObservables; |
| import org.eclipse.jface.databinding.swt.SWTObservables; |
| import org.eclipse.jface.layout.GridDataFactory; |
| import org.eclipse.jface.layout.GridLayoutFactory; |
| import org.eclipse.jface.viewers.CellEditor; |
| import org.eclipse.jface.viewers.ColumnLabelProvider; |
| import org.eclipse.jface.viewers.ColumnViewerEditor; |
| import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; |
| import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; |
| import org.eclipse.jface.viewers.ICellModifier; |
| import org.eclipse.jface.viewers.TextCellEditor; |
| import org.eclipse.jface.viewers.TreePath; |
| import org.eclipse.jface.viewers.TreeSelection; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.jface.viewers.TreeViewerColumn; |
| import org.eclipse.jface.viewers.TreeViewerEditor; |
| import org.eclipse.rcptt.core.model.ModelException; |
| import org.eclipse.rcptt.internal.ui.Q7UIPlugin; |
| import org.eclipse.rcptt.tesla.core.utils.WidgetModels; |
| import org.eclipse.rcptt.ui.controls.SectionWithComposite; |
| import org.eclipse.rcptt.ui.editors.EditorHeader; |
| import org.eclipse.rcptt.ui.verification.WidgetVerificationEditor; |
| import org.eclipse.rcptt.verifications.status.TreeItemVerificationError; |
| import org.eclipse.rcptt.verifications.tree.Cell; |
| import org.eclipse.rcptt.verifications.tree.Column; |
| import org.eclipse.rcptt.verifications.tree.Row; |
| import org.eclipse.rcptt.verifications.tree.Tree; |
| import org.eclipse.rcptt.verifications.tree.TreePackage; |
| import org.eclipse.rcptt.verifications.tree.TreeVerification; |
| import org.eclipse.rcptt.verifications.tree.TreeVerificationUtils; |
| import org.eclipse.rcptt.verifications.tree.VerifyStyleType; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.ImageData; |
| import org.eclipse.swt.graphics.ImageLoader; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Combo; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.TreeColumn; |
| import org.eclipse.swt.widgets.TreeItem; |
| import org.eclipse.ui.IWorkbenchSite; |
| import org.eclipse.ui.forms.IFormColors; |
| import org.eclipse.ui.forms.widgets.FormToolkit; |
| import org.eclipse.ui.forms.widgets.Section; |
| |
| public class TreeVerificationEditor extends WidgetVerificationEditor { |
| Binding treeDataBinding = null; |
| TreeTableObservable widgetObservable = null; |
| Combo verifyStyleCombo = null; |
| |
| public TreeVerification getVerificationElement() { |
| try { |
| return (TreeVerification) super.getElement().getNamedElement(); |
| } catch (ModelException e) { |
| Q7UIPlugin.log(e); |
| return null; |
| } |
| } |
| |
| public void dispose() { |
| super.dispose(); |
| } |
| |
| public Control create(Composite parent, FormToolkit toolkit, |
| IWorkbenchSite site, EditorHeader header) { |
| |
| Section section = new SectionWithComposite("Widget Tree", |
| Section.TITLE_BAR | Section.TWISTIE | Section.EXPANDED) |
| .create(parent, toolkit); |
| Composite client = (Composite) section.getClient(); |
| GridLayoutFactory.fillDefaults(). |
| numColumns(1). |
| spacing(SWT.DEFAULT, 16). |
| applyTo(client); |
| createWidgetControls(client, toolkit, site, header); |
| |
| Composite box = toolkit.createComposite(client); |
| GridDataFactory.fillDefaults().grab(true, true).applyTo(box); |
| GridLayoutFactory.fillDefaults() |
| .numColumns(1) |
| .spacing(16, 4) |
| .applyTo(box); |
| createControls(toolkit, box); |
| |
| header.getRecordButton().addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(final SelectionEvent e) { |
| Boolean defaultValue = (Boolean) TreePackage.Literals.VERIFY_TREE_DATA__ENABLE_VERIFY_STYLE |
| .getDefaultValue(); |
| getVerificationElement().setEnableVerifyStyle(defaultValue); |
| } |
| }); |
| |
| return section; |
| } |
| |
| private void createControls(final FormToolkit toolkit, |
| final Composite client) { |
| final Composite propertiesComposite = toolkit.createComposite(client); |
| GridDataFactory.fillDefaults().grab(true, false).applyTo(propertiesComposite); |
| GridLayoutFactory.fillDefaults().numColumns(4).applyTo(propertiesComposite); |
| createPropertiesControls(toolkit, propertiesComposite); |
| |
| Label introLabel = toolkit.createLabel(client, |
| "Widget tree should be:"); |
| introLabel |
| .setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); |
| introLabel.setBackground(null); |
| GridDataFactory.fillDefaults().applyTo(introLabel); |
| |
| final Composite treeComposite = toolkit.createComposite(client, SWT.BORDER | SWT.DOUBLE_BUFFERED); |
| GridDataFactory.fillDefaults().grab(true, true).applyTo(treeComposite); |
| GridLayoutFactory.fillDefaults().applyTo(treeComposite); |
| |
| widgetObservable = new TreeTableObservable(treeComposite); |
| treeDataBinding = dbc.bindValue(widgetObservable, EMFObservables.observeValue( |
| getVerificationElement(), |
| TreePackage.Literals.COMMON_TREE_VERIFICATION_DATA__TREE)); |
| } |
| |
| private void createPropertiesControls(final FormToolkit toolkit, |
| final Composite parent) { |
| |
| GridDataFactory align = GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.CENTER); |
| |
| Label verifyStyleLabel = toolkit.createLabel(parent, |
| "Verify styles:"); |
| verifyStyleLabel |
| .setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); |
| verifyStyleLabel.setBackground(null); |
| align.applyTo(verifyStyleLabel); |
| |
| verifyStyleCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY); |
| int selectedStyleInd = 0; |
| for (VerifyStyleType type : VerifyStyleType.values()) { |
| verifyStyleCombo.add(type.getLiteral()); |
| if (type.getValue() == getVerificationElement().getVerifyStyle().getValue()) { |
| selectedStyleInd = verifyStyleCombo.getItemCount() - 1; |
| } |
| } |
| verifyStyleCombo.select(selectedStyleInd); |
| verifyStyleCombo.addSelectionListener(new SelectionListener() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| getVerificationElement().setVerifyStyle(VerifyStyleType.get(verifyStyleCombo.getText())); |
| widgetObservable.updateOutputFormat(); |
| } |
| |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| } |
| }); |
| align.applyTo(verifyStyleCombo); |
| |
| Button unverifiedChildrenCheck = new Button(parent, SWT.CHECK); |
| unverifiedChildrenCheck.setText("Allow uncaptured children"); |
| unverifiedChildrenCheck |
| .setToolTipText("Tree items from verification without chirdren, may contain children in UI. " + |
| "This might happen when tree was not fully expanded during capturing."); |
| dbc.bindValue(SWTObservables.observeSelection(unverifiedChildrenCheck), |
| EMFObservables.observeValue(getVerificationElement(), |
| TreePackage.Literals.VERIFY_TREE_DATA__ALLOW_UNCAPTURED_CHILDREN)); |
| align.applyTo(unverifiedChildrenCheck); |
| |
| // Button missingColumnsCheck = new Button(parent, SWT.CHECK); |
| // missingColumnsCheck.setText("Allow missing columns"); |
| // missingColumnsCheck.setToolTipText("This verification may contain columns, which are not present in UI"); |
| // dbc.bindValue(SWTObservables.observeSelection(missingColumnsCheck), |
| // EMFObservables.observeValue(getVerificationElement(), |
| // TreePackage.Literals.VERIFY_TREE_DATA__ALLOW_MISSING_COLUMNS)); |
| |
| Button verifyIconsCheck = new Button(parent, SWT.CHECK); |
| verifyIconsCheck.setText("Verify icons"); |
| |
| dbc.bindValue(SWTObservables.observeSelection(verifyIconsCheck), |
| EMFObservables.observeValue(getVerificationElement(), |
| TreePackage.Literals.VERIFY_TREE_DATA__VERIFY_ICONS)); |
| verifyIconsCheck.addSelectionListener(new SelectionListener() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| widgetObservable.updateOutputFormat(); |
| } |
| |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| } |
| }); |
| align.applyTo(verifyIconsCheck); |
| } |
| |
| @Override |
| public void select(Object data) { |
| if (data instanceof TreeItemVerificationError) { |
| TreeItemVerificationError err = (TreeItemVerificationError) data; |
| |
| widgetObservable.selectItemAt(err.getItemIndexPath()); |
| } |
| } |
| |
| @Override |
| public void setSelectionAtLine(int line) { |
| } |
| |
| private class TreeTableObservable extends AbstractObservableValue { |
| private Composite treeComposite = null; |
| private TreeViewer viewer = null; |
| private VerificationTreeLabelProvider labelProvider = null; |
| private List<Image> columnImages = new ArrayList<Image>(); |
| |
| public TreeTableObservable(Composite treeComposite) { |
| this.treeComposite = treeComposite; |
| } |
| |
| public void updateOutputFormat() { |
| treeComposite.setRedraw(false); |
| if (labelProvider != null) { |
| labelProvider.setDrawIcons(getVerificationElement().isVerifyIcons()); |
| labelProvider |
| .setIgnoreStyle(getVerificationElement().getVerifyStyle() == VerifyStyleType.IGNORE_STYLES); |
| labelProvider |
| .setSkipStyledText( |
| getVerificationElement().getVerifyStyle() == VerifyStyleType.IGNORE_STYLED_TEXT); |
| } |
| if (viewer != null) { |
| TreeColumn[] cols = viewer.getTree().getColumns(); |
| if (getVerificationElement().isVerifyIcons()) { |
| for (int i = 0; i < cols.length; i++) { |
| if (i < columnImages.size()) |
| cols[i].setImage(columnImages.get(i)); |
| } |
| } else { |
| for (int i = 0; i < cols.length; i++) { |
| cols[i].setImage(null); |
| } |
| } |
| viewer.refresh(); |
| } |
| verifyStyleCombo.setEnabled(getVerificationElement().isEnableVerifyStyle()); |
| treeComposite.setRedraw(true); |
| } |
| |
| private TreePath toTreePath(List<Integer> indices) { |
| @SuppressWarnings("unchecked") |
| List<Row> rows = (List<Row>) viewer.getInput(); |
| List<Row> segments = new ArrayList<Row>(); |
| for (int i : indices) { |
| if (i < 0 || i >= rows.size()) { |
| break; |
| } |
| Row curr = rows.get(i); |
| segments.add(curr); |
| rows = curr.getChildren(); |
| } |
| return new TreePath(segments.toArray()); |
| } |
| |
| public void selectItemAt(List<Integer> itemIndexPath) throws IllegalArgumentException { |
| if (viewer != null && viewer.getTree() != null && itemIndexPath.size() > 0) { |
| TreePath treePath = toTreePath(itemIndexPath); |
| viewer.setSelection(new TreeSelection(treePath), true); |
| } |
| } |
| |
| @Override |
| public Object getValueType() { |
| return null; |
| } |
| |
| @Override |
| protected Object doGetValue() { |
| return null; |
| } |
| |
| @Override |
| protected void doSetValue(Object value) { |
| if (value instanceof Tree) { |
| Tree treeData = (Tree) value; |
| Map<String, Image> images = deserializeImages(treeComposite.getDisplay(), getVerificationElement() |
| .getImages()); |
| |
| treeComposite.setRedraw(false); |
| viewer = createTreeWidget(treeComposite, treeData, images); |
| |
| if (treeData.getSortColumnInd() != -1) { |
| viewer.getTree().setSortColumn(viewer.getTree().getColumn(treeData.getSortColumnInd())); |
| viewer.getTree().setSortDirection(treeData.getSortDirection()); |
| } |
| labelProvider = new VerificationTreeLabelProvider(images, |
| getVerificationElement().isVerifyIcons(), |
| getVerificationElement().getVerifyStyle() == VerifyStyleType.IGNORE_STYLES, |
| getVerificationElement().getVerifyStyle() == VerifyStyleType.IGNORE_STYLED_TEXT); |
| viewer.setLabelProvider(labelProvider); |
| viewer.setContentProvider(new VerificationTreeContentProvider()); |
| viewer.setInput(treeData.getRows()); |
| |
| viewer.expandAll(); |
| |
| widgetObservable.updateOutputFormat(); |
| |
| treeComposite.setRedraw(true); |
| } |
| } |
| |
| private Map<String, Image> deserializeImages(Display display, EMap<String, byte[]> images) { |
| Map<String, Image> result = new HashMap<String, Image>(); |
| for (Entry<String, byte[]> img : images.entrySet()) { |
| result.put(img.getKey(), deserializeImage(display, img.getValue())); |
| } |
| return result; |
| } |
| |
| private TreeViewer createTreeWidget(Composite parent, Tree treeData, Map<String, Image> images) { |
| for (Control control : parent.getChildren()) { |
| control.dispose(); |
| } |
| TreeViewer viewer = new TreeViewer(parent, treeData.getStyle() | SWT.FULL_SELECTION); |
| org.eclipse.swt.widgets.Tree tree = viewer.getTree(); |
| tree.setEnabled(treeData.isEnabled()); |
| tree.setHeaderVisible(treeData.isHeaderVisible()); |
| tree.setLinesVisible(treeData.isLinesVisible()); |
| tree.addListener(SWT.Selection, new Listener() { |
| public void handleEvent(Event event) { |
| if (event.detail == SWT.CHECK && (event.item instanceof TreeItem)) { |
| TreeItem item = (TreeItem) event.item; |
| item.setChecked(!item.getChecked()); |
| } |
| } |
| }); |
| |
| TreeViewerEditor.create(viewer, new ColumnViewerEditorActivationStrategy(viewer) { |
| protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) { |
| return (super.isEditorActivationEvent(event) && (getVerificationElement().getVerifyStyle() |
| .getValue() == VerifyStyleType.IGNORE_STYLED_TEXT_VALUE)); |
| } |
| }, ColumnViewerEditor.DEFAULT); |
| |
| String[] columnProperties = new String[treeData.getColumns().size()]; |
| CellEditor[] cellEditors = new CellEditor[treeData.getColumns().size()]; |
| |
| for (int columnNum = 0; columnNum < treeData.getColumns().size(); columnNum++) { |
| final TreeViewerColumn column = new TreeViewerColumn(viewer, SWT.NONE); |
| |
| // apply only for table verifications |
| Column treeColumn = treeData.getColumns().get(columnNum); |
| column.getColumn().setText(treeColumn.getName()); |
| column.getColumn().setWidth(treeColumn.getWidth()); |
| column.getColumn().setToolTipText(treeColumn.getTooltip()); |
| |
| String imgPath = TreeVerificationUtils.getDecoratedImagePath(treeColumn.getImage()); |
| if (images.containsKey(imgPath)) { |
| Image img = images.get(imgPath); |
| columnImages.add(img); |
| if (getVerificationElement().isVerifyIcons()) { |
| column.getColumn().setImage(img); |
| } |
| } else { |
| columnImages.add(null); |
| } |
| column.setLabelProvider(new ColumnLabelProvider()); |
| columnProperties[columnNum] = "" + columnNum; |
| cellEditors[columnNum] = new TextCellEditor(tree); |
| } |
| |
| if (treeData.getColumns().size() == 0) { |
| // initial for tree |
| viewer.setColumnProperties(new String[] { "0" }); |
| viewer.setCellEditors(new CellEditor[] { new TextCellEditor(tree) }); |
| } else { |
| viewer.setColumnProperties(columnProperties); |
| viewer.setCellEditors(cellEditors); |
| } |
| |
| viewer.setCellModifier(new ICellModifier() { |
| public void modify(Object element, String property, Object value) { |
| String newValue = (String) value; |
| int index = Integer.parseInt(property); |
| if (((TreeItem) element).getData() instanceof Row) { |
| Cell cellItem = ((Row) ((TreeItem) element).getData()).getValues().get(index); |
| if (newValue != null && !cellItem.getData().getText().equals(newValue)) { |
| cellItem.getData().setText(newValue); |
| cellItem.getStyle().clear(); |
| getVerificationElement().setEnableVerifyStyle(false); |
| updateOutputFormat(); |
| } |
| } |
| } |
| |
| public Object getValue(Object element, String property) { |
| String result = ""; |
| if (element instanceof Row) { |
| int index = Integer.parseInt(property); |
| Cell cellItem = ((Row) element).getValues().get(index); |
| result = WidgetModels.getTextWithoutStyle(cellItem.getStyle(), cellItem.getData().getText()); |
| } |
| return result; |
| } |
| |
| public boolean canModify(Object element, String property) { |
| return getVerificationElement().getVerifyStyle() |
| .getValue() == VerifyStyleType.IGNORE_STYLED_TEXT_VALUE; |
| } |
| }); |
| |
| GridDataFactory.fillDefaults().grab(true, true).hint(100, 10).applyTo(viewer.getTree()); |
| parent.layout(true, true); |
| |
| return viewer; |
| } |
| } |
| |
| private static byte[] serializeImage(Image img) { |
| ImageLoader imageLoader = new ImageLoader(); |
| imageLoader.data = new ImageData[] { img.getImageData() }; |
| ByteArrayOutputStream stream = new ByteArrayOutputStream(); |
| imageLoader.save(stream, SWT.IMAGE_PNG); |
| return stream.toByteArray(); |
| } |
| |
| private static Image deserializeImage(Display display, byte[] img) { |
| ImageLoader imageLoader = new ImageLoader(); |
| ByteArrayInputStream stream = new ByteArrayInputStream(img); |
| ImageData[] data = imageLoader.load(stream); |
| return new Image(display, data[0]); |
| } |
| } |