Java tutorial
/* uDig - User Friendly Desktop Internet GIS client * http://udig.refractions.net * (C) 2004, Refractions Research Inc. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). */ package org.locationtech.udig.validation.ui; import java.beans.IntrospectionException; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.locationtech.udig.issues.IIssuesManager; import org.locationtech.udig.issues.IssueConstants; import org.locationtech.udig.project.ILayer; import org.locationtech.udig.project.IMap; import org.locationtech.udig.project.ui.ApplicationGIS; import org.locationtech.udig.ui.PlatformGIS; import org.locationtech.udig.ui.graphics.TableSettings; import org.locationtech.udig.ui.graphics.TableUtils; import org.locationtech.udig.validation.DTOUtils; import org.locationtech.udig.validation.GenericValidationResults; import org.locationtech.udig.validation.ImageConstants; import org.locationtech.udig.validation.ValidationPlugin; import org.locationtech.udig.validation.ValidationProcessor; import org.locationtech.udig.validation.internal.Messages; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.TitleAreaDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.wizard.ProgressMonitorPart; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; 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.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.model.WorkbenchViewerSorter; import org.geotools.validation.Validation; import org.geotools.validation.dto.ArgumentDTO; import org.geotools.validation.dto.PlugInDTO; import org.geotools.validation.dto.TestDTO; import org.geotools.validation.dto.TestSuiteDTO; import org.geotools.validation.xml.ValidationException; import org.geotools.validation.xml.XMLReader; import org.geotools.validation.xml.XMLWriter; import org.opengis.feature.simple.SimpleFeatureType; public class ValidationDialog extends TitleAreaDialog { /** * Constant to use as the key for storing the validation processor on the * blackboard (for saving the state of the validation dialog box) */ public static final String BLACKBOARD_KEY = "org.locationtech.udig.validation"; //$NON-NLS-1$ private Button newButton; private Button deleteButton; private Button exportButton; private Button importButton; private Button runButton; private Button cancelButton; private Composite buttonComposite; private SelectionListener closeListener; private SelectionListener cancelListener; private Text nameText; private Text descText; private TableViewer tableViewer; private TableSettings tableSettings; private CheckboxTreeViewer treeViewer; private ValidationTreeContentProvider contentProvider = null; private ProgressMonitorPart progressMonitorPart; private Object selectedTreeItem; private ValidationProcessor processor; /** The key (name) of the testSuite in use (usually there will only be a * single testSuite, and this is its name). */ private String defaultTestSuite; /** If a layer was selected to get to this dialog, it is the default testSuite. * Otherwise the value is "" or even "*". */ private String defaultTypeRef = ""; //$NON-NLS-1$ private Display display; private static String[] typeRefs; private static String[] layerNames; //private ILayer[] layers; public ValidationDialog(Shell parentShell, ILayer[] layers) { this(parentShell); // determine the defaultTypeRef (from the first selected layer) String dsID = layers[0].getSchema().getName().getNamespaceURI(); String typeName = layers[0].getName(); defaultTypeRef = dsID + ":" + typeName; //$NON-NLS-1$ //this.layers = layers; display = parentShell.getDisplay(); cancelListener = new SelectionListener() { public void widgetSelected(SelectionEvent e) { // a test is running and the user just hit cancel // cancel the progress monitor progressMonitorPart.setCanceled(true); cancelButton.setEnabled(false); } public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } }; } protected ValidationDialog(Shell parentShell) { super(parentShell); setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL | getDefaultOrientation()); setBlockOnOpen(true); } public ValidationDialog getDialog() { return this; } public Button getCancelButton() { return cancelButton; } @Override protected Control createButtonBar(Composite parent) { Composite composite = new Composite(parent, SWT.FILL); GridLayout layout = new GridLayout(); layout.numColumns = 2; layout.makeColumnsEqualWidth = true; layout.marginWidth = 0; // no spacing here, it's purely a container layout.marginHeight = 0; layout.horizontalSpacing = 0; layout.verticalSpacing = 0; composite.setLayout(layout); GridData data = new GridData(SWT.FILL, SWT.CENTER, true, false); composite.setLayoutData(data); composite.setFont(parent.getFont()); // create 2 composites in the composite with left and right aligns Composite leftComp = new Composite(composite, SWT.LEFT); layout = new GridLayout(); layout.numColumns = 2; layout.makeColumnsEqualWidth = true; layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); leftComp.setLayout(layout); data = new GridData(SWT.LEFT, SWT.NONE, true, false); leftComp.setLayoutData(data); leftComp.setFont(parent.getFont()); Composite rightComp = new Composite(composite, SWT.RIGHT); layout = new GridLayout(); layout.numColumns = 2; layout.makeColumnsEqualWidth = true; layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); rightComp.setLayout(layout); data = new GridData(SWT.RIGHT, SWT.NONE, true, false); rightComp.setLayoutData(data); rightComp.setFont(parent.getFont()); // Add the buttons importButton = new Button(leftComp, SWT.PUSH); importButton.setFont(parent.getFont()); importButton.setText(Messages.ValidationDialog_import); importButton.setEnabled(true); importButton.addSelectionListener(new ImportSuiteListener()); setButtonLayoutData(importButton); exportButton = new Button(leftComp, SWT.PUSH); exportButton.setFont(parent.getFont()); exportButton.setText(Messages.ValidationDialog_export); exportButton.setEnabled(false); exportButton.addSelectionListener(new ExportSuiteListener()); setButtonLayoutData(exportButton); runButton = new Button(rightComp, SWT.PUSH); runButton.setFont(parent.getFont()); runButton.setText(Messages.ValidationDialog_run); runButton.setEnabled(false); runButton.addSelectionListener(new RunTestsListener()); setButtonLayoutData(runButton); cancelButton = new Button(rightComp, SWT.PUSH); cancelButton.setText(IDialogConstants.CLOSE_LABEL); cancelButton.setFont(parent.getFont()); cancelButton.setData(new Integer(IDialogConstants.CANCEL_ID)); closeListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { // nothing is happening and the user hit cancel (close) buttonPressed(((Integer) event.widget.getData()).intValue()); } }; // cancelListener = new SelectionListener() { // // public void widgetSelected( SelectionEvent e ) { // // a test is running and the user just hit cancel // // cancel the progress monitor // progressMonitorPart.setCanceled(true); // cancelButton.setEnabled(false); // } // // public void widgetDefaultSelected( SelectionEvent e ) { // widgetSelected(e); // } // // }; cancelButton.addSelectionListener(closeListener); setButtonLayoutData(cancelButton); return composite; } @Override protected void createButtonsForButtonBar(Composite parent) { } @Override protected Control createDialogArea(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); setTitle(Messages.ValidationDialog_title); setMessage(""); //$NON-NLS-1$ ImageDescriptor image = ValidationPlugin.getDefault().getImageDescriptor(ImageConstants.IMAGE_WIZBAN); if (image != null) setTitleImage(image.createImage()); GridData gd; gd = new GridData(SWT.FILL, SWT.FILL, true, true); composite.setLayoutData(gd); GridLayout topLayout = new GridLayout(1, false); topLayout.marginHeight = 0; topLayout.marginWidth = 0; composite.setLayout(topLayout); // Create the SashForm that contains the selection area on the left, // and the edit area on the right SashForm sashForm = new SashForm(composite, SWT.FILL); sashForm.setOrientation(SWT.HORIZONTAL); gd = new GridData(SWT.FILL, SWT.FILL, true, true); sashForm.setLayoutData(gd); sashForm.setFont(parent.getFont()); // Build the validation selection area and put it into the composite. Composite validationSelectionArea; try { validationSelectionArea = createValidationSelectionArea(sashForm); } catch (Exception e) { // TODO Handle Exception throw (RuntimeException) new RuntimeException().initCause(e); } gd = new GridData(SWT.FILL, SWT.FILL, true, true); validationSelectionArea.setLayoutData(gd); // Build the validation edit area and put it into the composite. Composite editAreaComp = createValidationEditArea(sashForm); gd = new GridData(SWT.FILL, SWT.FILL, true, true); editAreaComp.setLayoutData(gd); // add the progress bar GridLayout pmlayout = new GridLayout(); pmlayout.numColumns = 1; progressMonitorPart = createProgressMonitorPart(composite, pmlayout); progressMonitorPart.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); progressMonitorPart.setVisible(false); // Build the separator line that demarcates the button bar Label separator = new Label(composite, SWT.HORIZONTAL | SWT.SEPARATOR); gd = new GridData(SWT.FILL, SWT.NONE, true, false); // gd.horizontalSpan = 2; separator.setLayoutData(gd); parent.layout(true); applyDialogFont(parent); // create a resize listener composite.addListener(SWT.Resize, new Listener() { public void handleEvent(Event event) { resizeTable(); // FIXME: possibly move this listener to the table.resize event } }); composite.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { // find the Map IMap map = ApplicationGIS.getActiveMap(); saveDialogState(processor, map); } }); return composite; } /** * Creates the validation test suite selection area of the dialog. This area displays a tree of * validations that the user may select and modify. The first tier of the tree contains the * available validation plugins, and the second tier contains instances of the test. * * @return the composite used for the validations selection area * @throws Exception */ protected Composite createValidationSelectionArea(Composite parent) throws Exception { Font font = parent.getFont(); Composite comp = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(1, false); layout.marginHeight = 5; layout.marginWidth = 5; comp.setLayout(layout); comp.setFont(font); Label treeLabel = new Label(comp, SWT.NONE); treeLabel.setFont(font); treeLabel.setText(Messages.ValidationDialog_validations); GridData labelData = new GridData(); treeLabel.setLayoutData(labelData); ValidationProcessor tempProcessor = loadDialogState(ApplicationGIS.getActiveMap()); if (tempProcessor == null) { processor = createProcessor(null, null); defaultTestSuite = "testSuite1"; //$NON-NLS-1$ } else { processor = tempProcessor; if (processor.getTestSuiteDTOs().size() == 1) { // a single testSuite exists, grab its name defaultTestSuite = (String) processor.getTestSuiteDTOs().keySet().toArray()[0]; } else if (processor.getTestSuiteDTOs().size() == 0) { // there is no... testSuite, create one processor = createProcessor(null, null); defaultTestSuite = "testSuite1"; //$NON-NLS-1$ } else { // there are multiple testSuites, choose the largest one String thisTestSuite = ""; //$NON-NLS-1$ int mostTests = -1; for (Iterator i = processor.getTestSuiteDTOs().keySet().iterator(); i.hasNext();) { Object thisKey = i.next(); int numTests = ((TestSuiteDTO) processor.getTestSuiteDTOs().get(thisKey)).getTests().size(); if (numTests > mostTests) { mostTests = numTests; thisTestSuite = (String) thisKey; } } defaultTestSuite = thisTestSuite; } } // create the treeViewer (list of possible validations (plugins) + prepared tests) treeViewer = new CheckboxTreeViewer(comp); treeViewer.setLabelProvider(new ValidationTreeLabelProvider()); treeViewer.setSorter(new WorkbenchViewerSorter()); contentProvider = new ValidationTreeContentProvider(); treeViewer.setContentProvider(contentProvider); treeViewer.addCheckStateListener(new ICheckStateListener() { public void checkStateChanged(CheckStateChangedEvent event) { Object element = event.getElement(); Object[] children = contentProvider.getChildren(element); if (children != null && children.length > 0) { // parent element was modified, adjust the children accordingly for (int i = 0; i < children.length; i++) { treeViewer.setChecked(children[i], event.getChecked()); } // all children are in the same state, therefore the parent is not grayed treeViewer.setGrayed(element, false); } Object parent = contentProvider.getParent(element); if (parent != null) { // child element was modified Object[] siblings = contentProvider.getChildren(parent); boolean oneSiblingChecked = false; boolean allSiblingsChecked = true; for (int i = 0; i < siblings.length; i++) { if (treeViewer.getChecked(siblings[i])) { oneSiblingChecked = true; } else { allSiblingsChecked = false; } } if (allSiblingsChecked) { // mark parent checked and NOT grayed out treeViewer.setGrayed(parent, false); treeViewer.setChecked(parent, true); } else { if (oneSiblingChecked) { // mark parent checked and grayed out treeViewer.setGrayChecked(parent, true); } else { // mark parent NOT checked treeViewer.setGrayChecked(parent, false); } } } } }); // populate the tree treeViewer.setInput(processor); treeViewer.expandAll(); Control control = treeViewer.getControl(); GridData gd = new GridData(GridData.FILL_BOTH); gd.heightHint = 250; // initial height of treeViewer (in pixels?) gd.verticalSpan = 3; control.setLayoutData(gd); control.setFont(font); // composite to hold the new/delete/save/... buttons buttonComposite = new Composite(comp, SWT.NONE); gd = new GridData(GridData.FILL_HORIZONTAL); gd.widthHint = 200; buttonComposite.setLayoutData(gd); buttonComposite.setFont(comp.getFont()); GridLayout buttonLayout = new GridLayout(2, false); buttonComposite.setLayout(buttonLayout); // construct the new validation test button newButton = new Button(buttonComposite, SWT.PUSH); newButton.setFont(parent.getFont()); newButton.setText(Messages.ValidationDialog_new); newButton.setEnabled(false); newButton.addSelectionListener(new NewTestListener()); setButtonLayoutData(newButton); // construct the delete validation test button deleteButton = new Button(buttonComposite, SWT.PUSH); deleteButton.setFont(parent.getFont()); deleteButton.setText(Messages.ValidationDialog_delete); deleteButton.setEnabled(false); deleteButton.addSelectionListener(new DeleteTestListener()); setButtonLayoutData(deleteButton); // construct treeViewer listener treeViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { if (!event.getSelection().isEmpty()) { StructuredSelection selection = (StructuredSelection) event.getSelection(); if (selection.size() == 1) { Object element = selection.getFirstElement(); selectedTreeItem = element; //record the current selection so other events can figure out who is selected if (element instanceof TestDTO) { //test instance was selected newButton.setEnabled(false); deleteButton.setEnabled(true); nameText.setText(((TestDTO) element).getName()); nameText.setEditable(true); descText.setText(((TestDTO) element).getDescription()); descText.setEditable(true); tableViewer.setInput(element); // pass the args (inside the testDTO) tableViewer.getControl().setEnabled(true); resizeTable(); } else if (element instanceof PlugInDTO) { //validation parent (plugin) was selection newButton.setEnabled(true); deleteButton.setEnabled(false); nameText.setText(((PlugInDTO) selection.getFirstElement()).getName()); nameText.setEditable(false); descText.setText(((PlugInDTO) selection.getFirstElement()).getDescription()); descText.setEditable(false); tableViewer.setInput(null); //hide arguments tableViewer.getControl().setEnabled(false); } else { // this shouldn't be called newButton.setEnabled(false); deleteButton.setEnabled(false); nameText.setText(""); //$NON-NLS-1$ nameText.setEditable(false); descText.setText(""); //$NON-NLS-1$ descText.setEditable(false); tableViewer.setInput(null); //hide arguments tableViewer.getControl().setEnabled(false); } } else { //more than one selection was made selectedTreeItem = null; newButton.setEnabled(false); deleteButton.setEnabled(false); nameText.setEditable(false); descText.setEditable(false); tableViewer.setInput(null); //hide arguments tableViewer.getControl().setEnabled(false); } updateButtons(); } } }); treeViewer.addCheckStateListener(new ICheckStateListener() { public void checkStateChanged(CheckStateChangedEvent event) { updateButtons(); if (event.getElement() instanceof PlugInDTO) { if (event.getChecked()) { //select the parent if is not already ISelection selection; if (selectedTreeItem != event.getElement()) { selection = new StructuredSelection(event.getElement()); treeViewer.setSelection(selection); } //automatically create a child if none exist if (!contentProvider.hasChildren(selectedTreeItem)) { TestDTO newTest = addTest(); selection = new StructuredSelection(newTest); treeViewer.setSelection(selection); } } } } }); return comp; } /** * Creates the validations edit area of the dialog. This area displays the name and description * of the validation test currently selected. Instances of plugins may only be viewed, while * instances of validation tests (within the testSuite) may be modified. * * @return the composite used for launch configuration editing */ protected Composite createValidationEditArea(Composite parent) { // create a composite to place our form objects into Font font = parent.getFont(); Composite comp = new Composite(parent, SWT.NONE); // setSelectionArea(comp); GridLayout layout = new GridLayout(1, false); layout.marginHeight = 5; layout.marginWidth = 5; comp.setLayout(layout); comp.setFont(font); // create the "name" label Label nameLabel = new Label(comp, SWT.TOP | SWT.LEFT); nameLabel.setFont(font); nameLabel.setText(Messages.ValidationDialog_name); GridData gd = new GridData(); nameLabel.setLayoutData(gd); // create the "name" text box nameText = new Text(comp, SWT.BORDER | SWT.SINGLE | SWT.FILL); gd = new GridData(SWT.FILL, SWT.TOP, true, false); nameText.setLayoutData(gd); nameText.addModifyListener(new NameModifiedListener()); // create the "description" label Label descLabel = new Label(comp, SWT.TOP | SWT.LEFT); descLabel.setFont(font); descLabel.setText(Messages.ValidationDialog_description); gd = new GridData(); nameLabel.setLayoutData(gd); // create the "description" text box descText = new Text(comp, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); gd = new GridData(SWT.FILL, SWT.TOP, true, false); gd.heightHint = 60; descText.setLayoutData(gd); descText.addModifyListener(new DescModifiedListener()); // create a new table object Table table = new Table(comp, SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.RESIZE); // create a tableViewer containing the table tableViewer = createTable(table); tableViewer.setContentProvider(new ValidationTableContentProvider()); tableViewer.setLabelProvider(new ValidationTableLabelProvider()); tableViewer.setInput(null); Control control = tableViewer.getControl(); gd = new GridData(GridData.FILL_BOTH); gd.heightHint = 200; // initial height of treeViewer (in pixels?) control.setLayoutData(gd); control.setFont(font); tableViewer.setCellModifier(new CellModifiedListener()); CellEditor[] editors = new CellEditor[2]; editors[0] = null; Object[] allLayers = ApplicationGIS.getActiveMap().getMapLayers().toArray(); ArrayList<String> typeRefsList = new ArrayList<String>(); ArrayList<String> layerNamesList = new ArrayList<String>(); typeRefsList.add(""); //$NON-NLS-1$ layerNamesList.add(""); //$NON-NLS-1$ typeRefsList.add("*"); //$NON-NLS-1$ layerNamesList.add("*"); //$NON-NLS-1$ for (int i = 0; i < allLayers.length; i++) { ILayer thisLayer = (ILayer) allLayers[i]; SimpleFeatureType schema = thisLayer.getSchema(); if (schema == null) continue; String dsID = schema.getName().getNamespaceURI(); String typeName = thisLayer.getName(); if (dsID == null || typeName == null) continue; typeRefsList.add(dsID + ":" + typeName); //$NON-NLS-1$ layerNamesList.add(typeName); } typeRefs = typeRefsList.toArray(new String[typeRefsList.size()]); layerNames = layerNamesList.toArray(new String[layerNamesList.size()]); // create the text/combo cell editor editors[1] = new AmbiguousCellEditor((Composite) table, table, layerNamesList, typeRefsList); // only the layer names will show up in the combo, but typeRef is the real value tableViewer.setCellEditors(editors); // note: Argument and Value below are internal tags, not labels tableViewer.setColumnProperties(new String[] { "Argument", "Value" }); //$NON-NLS-1$//$NON-NLS-2$ // create a table settings object and configure it tableSettings = new TableSettings(table); tableSettings.setColumnMin(0, 65); return comp; } protected TableViewer createTable(Table table) { TableViewer tableViewer = new TableViewer(table); TableLayout layout = new TableLayout(); layout.addColumnData(new ColumnWeightData(50, 65, true)); TableColumn nameColumn = new TableColumn(table, SWT.LEFT); nameColumn.setText(Messages.ValidationDialog_argument); nameColumn.setWidth(65); layout.addColumnData(new ColumnWeightData(50, 75, true)); table.setLayout(layout); TableColumn valColumn = new TableColumn(table, SWT.LEFT); valColumn.setText(Messages.ValidationDialog_value); valColumn.setWidth(75); table.setHeaderVisible(true); table.setLinesVisible(true); return tableViewer; } /** * Create the progress monitor part in the receiver. * * @param composite * @param pmlayout * @return ProgressMonitorPart */ protected ProgressMonitorPart createProgressMonitorPart(Composite composite, GridLayout pmlayout) { return new ProgressMonitorPart(composite, pmlayout, SWT.DEFAULT) { String currentTask = null; boolean lockedUI = false; /* * (non-Javadoc) * * @see org.eclipse.jface.wizard.ProgressMonitorPart#setBlocked(org.eclipse.core.runtime.IStatus) */ public void setBlocked(IStatus reason) { super.setBlocked(reason); if (!lockedUI)// Do not show blocked if we are locking the UI getBlockedHandler().showBlocked(getShell(), this, reason, currentTask); } /* * (non-Javadoc) * * @see org.eclipse.jface.wizard.ProgressMonitorPart#clearBlocked() */ public void clearBlocked() { super.clearBlocked(); if (!lockedUI)// Do not clear if we never set it getBlockedHandler().clearBlocked(); } /* * (non-Javadoc) * * @see org.eclipse.jface.wizard.ProgressMonitorPart#beginTask(java.lang.String, int) */ public void beginTask(String name, int totalWork) { super.beginTask(name, totalWork); currentTask = name; } /* * (non-Javadoc) * * @see org.eclipse.jface.wizard.ProgressMonitorPart#setTaskName(java.lang.String) */ public void setTaskName(String name) { super.setTaskName(name); currentTask = name; } /* * (non-Javadoc) * * @see org.eclipse.jface.wizard.ProgressMonitorPart#subTask(java.lang.String) */ public void subTask(String name) { super.subTask(name); // If we haven't got anything yet use this value for more context if (currentTask == null) currentTask = name; } }; } //TODO: implement runValidationTestsOptimized private GenericValidationResults[] runValidationTestsUnOptimized(IProgressMonitor monitor, Object[] element) throws Exception { //wander through the tree and run each enabled test in the processor individually //filter out the pluginDTOs, leaving only the TestDTOs List<TestDTO> tests = new ArrayList<TestDTO>(); for (int i = 0; i < element.length; i++) { if (element[i] instanceof TestDTO) { tests.add((TestDTO) element[i]); } } if (monitor == null) monitor = new NullProgressMonitor(); monitor.beginTask(Messages.ValidationDialog_validating + Messages.ValidationDialog_ellipsis, (tests.size() * 11) + 2); //update the Lookup Maps processor.updateFVLookup(); //processor.updateIVLookup(); monitor.worked(1); //TODO: ensure typeRefs are copied //monitor.beginTask("Running Tests", tests.size()); //FIXME: use the selected map rather than layer[0] ILayer[] layers = (ILayer[]) ApplicationGIS.getActiveMap().getMapLayers().toArray(); //perform feature tests GenericValidationResults[] results = new GenericValidationResults[tests.size()]; //open the issues list openIssuesList(); monitor.worked(1); for (int i = 0; i < tests.size(); i++) { results[i] = new GenericValidationResults(); //check for cancellation if (monitor.isCanceled()) { break; } //proceed String testName = tests.get(i).getName(); //TODO: run as either feature or integrity test monitor.subTask(""); //$NON-NLS-1$ monitor.setTaskName( Messages.ValidationDialog_validating + " " + testName + Messages.ValidationDialog_ellipsis); SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 10); processor.runFeatureTest(testName, layers, results[i], subMonitor); //processor.runIntegrityTest(test.getName(), layers, results[i], monitor); //check for cancellation again... if (subMonitor.isCanceled()) { monitor.setCanceled(true); } if (monitor.isCanceled()) { break; } //add to issues list monitor.subTask(MessageFormat.format(Messages.ValidationDialog_populating, testName)); IIssuesManager.defaultInstance.getIssuesList().addAll(results[i].issues); monitor.worked(1); } monitor.done(); return results; } /** * Based on the name of the argument, this function determines if it is a * typeRef or not. * * @param argName * @return */ public static boolean isTypeRef(String argName) { if (argName.toLowerCase().contains("typeref")) //$NON-NLS-1$ return true; else return false; } public static String getTypeRefLayer(String typeRef) { for (int i = 0; i < typeRefs.length; i++) { if (typeRefs[i].equals(typeRef)) { return layerNames[i]; } } return null; } /** * Creates a validation processor. Both parameters may be null. * * @param pluginsDir * @param testSuiteFile * @return * @throws Exception */ private ValidationProcessor createProcessor(File pluginsDir, File testSuiteFile) throws Exception { if (pluginsDir == null) { URL pluginURL = ValidationPlugin.getDefault().getBundle().getResource("plugins"); //$NON-NLS-1$ String pluginsPath = Platform.asLocalURL(pluginURL).getFile(); // String pluginsPath = FileLocator.toFileURL(pluginURL).getFile(); pluginsDir = new File(pluginsPath); } return new ValidationProcessor(pluginsDir, testSuiteFile); } /** * Resizes the table columns to behave better. * * @param table */ private void resizeTable() { Table table = tableViewer.getTable(); TableUtils.resizeColumns(table, tableSettings, TableUtils.MODE_LAZY); } /** * Sets the given cursor for all shells currently active * for this window's display. * * @param c the cursor */ private void setDisplayCursor(Cursor c) { Shell[] shells = display.getShells(); for (int i = 0; i < shells.length; i++) shells[i].setCursor(c); } /** Enables/Disables the buttons as appropriate */ private void updateButtons() { //check to see if any tests exist in the testSuite boolean testsExist; testsExist = processor.testsExist(defaultTestSuite); exportButton.setEnabled(testsExist); //only allow tests to be run when at least one is enabled boolean testsEnabled = false; if (testsExist) { Object[] elements = treeViewer.getCheckedElements(); for (int i = 0; i < elements.length; i++) { if (elements[i] instanceof TestDTO) { testsEnabled = true; break; } } } runButton.setEnabled(testsEnabled); if (treeViewer.getSelection().isEmpty()) { newButton.setEnabled(false); deleteButton.setEnabled(false); } //clear the message bar (validation complete) setMessage(""); //$NON-NLS-1$ } private void openIssuesList() throws PartInitException { if (Display.getCurrent() != null) try { PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() .showView(IssueConstants.VIEW_ID); } catch (PartInitException e) { ValidationPlugin.log("error opening issues view", e); //$NON-NLS-1$ } else { display.asyncExec(new Runnable() { public void run() { try { PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() .showView(IssueConstants.VIEW_ID); } catch (PartInitException e) { ValidationPlugin.log("error opening issues view", e); //$NON-NLS-1$ } } }); } } private class DescModifiedListener implements ModifyListener { /** * Saves changes made to the description field */ public void modifyText(ModifyEvent e) { //ensure this is a validation test description (plugin descriptions cannot be modified) if (selectedTreeItem instanceof TestDTO) { //save the text TestDTO treeItem = ((TestDTO) selectedTreeItem); treeItem.setDescription(descText.getText()); } } } private class CellModifiedListener implements ICellModifier { public boolean canModify(Object element, String property) { return true; } public Object getValue(Object element, String property) { if (property.equals("Argument")) //$NON-NLS-1$ return ((ArgumentDTO) element).getName(); else { Object value = ((ArgumentDTO) element).getValue(); //on read of arg value: null --> "" //on write of arg value: "" --> null if (value == null) return ""; //$NON-NLS-1$ else return value; } } public void modify(Object element, String property, Object value) { if (property.equals("Value")) { //$NON-NLS-1$ //store the new value in the testSuite TableItem tableItem = (TableItem) element; ArgumentDTO arg = (ArgumentDTO) tableItem.getData(); if (value instanceof Integer) { //comboBox if (value.equals(-1)) arg.setValue(""); //$NON-NLS-1$ else { int val = (Integer) value; arg.setValue(typeRefs[val]); } } else if (value instanceof String) { //textBox //on read of arg value: null --> "" //on write of arg value: "" --> null if (value.equals("")) //$NON-NLS-1$ arg.setValue(null); else arg.setValue(value); } tableViewer.refresh(); //update the argument value in the validation test lookups (FV and IV) try { processor.setArg((TestDTO) selectedTreeItem, arg); } catch (ValidationException e) { // TODO Handle ValidationException throw (RuntimeException) new RuntimeException().initCause(e); } catch (IntrospectionException e) { // TODO Handle IntrospectionException throw (RuntimeException) new RuntimeException().initCause(e); } } } } private class NameModifiedListener implements ModifyListener { /** * Saves changes made to the name field */ public void modifyText(ModifyEvent e) { //ensure this is a validation test description (plugin descriptions cannot be modified) if (selectedTreeItem instanceof TestDTO) { //save the text TestDTO treeItem = ((TestDTO) selectedTreeItem); boolean renameSuccess = processor.renameValidation(treeItem.getName(), nameText.getText(), defaultTestSuite); if (renameSuccess) { treeViewer.refresh(); getDialog().setErrorMessage(null); } else { //user tried to create 2 identical test names -- complain. getDialog().setErrorMessage(Messages.ValidationDialog_nonUniqueTest); } } } } private TestDTO addTest() { Object selection = selectedTreeItem; TestDTO thisTest = null; //plugin is selected? if (selection instanceof PlugInDTO) { // create a new validation test object PlugInDTO plugin = (PlugInDTO) selection; Validation newTest = null; try { newTest = processor.createValidation(plugin); } catch (Exception e1) { // log the exception and return MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Exception Occurred", e1.getClass().toString() + " " + e1.getMessage()); //$NON-NLS-1$//$NON-NLS-2$ ValidationPlugin.log(e1.getMessage(), e1); return null; } // determine which TestSuiteDTO to use (for now, use the default) String testSuiteDTOKey = defaultTestSuite; // add the validation to the processor (creates a testDTO // and adds the validation to the appropriate lookup) processor.addValidation(newTest, plugin, testSuiteDTOKey); // if a defaultTypeRef exists, set any typeRefs to that value if ((defaultTypeRef != null) && defaultTypeRef.length() > 0) { thisTest = (TestDTO) processor.getTests().get(newTest.getName()); Map args = thisTest.getArgs(); for (Iterator i = args.keySet().iterator(); i.hasNext();) { ArgumentDTO arg = (ArgumentDTO) args.get(i.next()); String argName = arg.getName(); //is it a typeRef? if (isTypeRef(argName)) { //is it empty? if (arg.getValue() == null || arg.getValue().toString().length() == 0) { arg.setValue(defaultTypeRef); } } } } //if the current item is not expanded, expand it to show the new item if (!treeViewer.getExpandedState(selectedTreeItem)) { treeViewer.setExpandedState(selectedTreeItem, true); } //if the current parent test is checked and not grayed, check off the new test if (treeViewer.getChecked(selectedTreeItem) && !treeViewer.getGrayed(selectedTreeItem)) { treeViewer.setChecked(thisTest, true); } //refresh treeViewer.refresh(); updateButtons(); } return thisTest; } private class NewTestListener implements SelectionListener { public void widgetSelected(SelectionEvent e) { addTest(); } public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } } private class DeleteTestListener implements SelectionListener { public void widgetSelected(SelectionEvent e) { Object selection = selectedTreeItem; //a test is selected? if (selection instanceof TestDTO) { //find the validation, given the TestDTO TestDTO test = (TestDTO) selection; //delete the validation test processor.removeValidation(test); treeViewer.refresh(); updateButtons(); } } public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } } private class RunTestsListener implements SelectionListener { GenericValidationResults[] results = new GenericValidationResults[0]; public void widgetSelected(final SelectionEvent e) { final Object[] element = treeViewer.getCheckedElements(); IRunnableWithProgress process = new IRunnableWithProgress() { public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { results = runValidationTestsUnOptimized(monitor, element); } catch (Exception e) { monitor.setCanceled(true); ValidationPlugin.log("Error running validation Tests", e); //$NON-NLS-1$ } } }; Control focusControl = null; Cursor arrowCursor = null; Cursor waitCursor = null; try { focusControl = display.getFocusControl(); progressMonitorPart.setVisible(true); runButton.setEnabled(false); cancelButton.removeSelectionListener(closeListener); cancelButton.addSelectionListener(cancelListener); waitCursor = new Cursor(display, SWT.CURSOR_WAIT); setDisplayCursor(waitCursor); // Set the arrow cursor to the cancel component. arrowCursor = new Cursor(display, SWT.CURSOR_ARROW); cancelButton.setText(IDialogConstants.CANCEL_LABEL); cancelButton.setCursor(arrowCursor); cancelButton.setFocus(); setMessage("Validation in progress..."); PlatformGIS.runBlockingOperation(process, progressMonitorPart); //progressMonitorPart.setVisible(false); } catch (InvocationTargetException e1) { // TODO Handle InvocationTargetException throw (RuntimeException) new RuntimeException().initCause(e1); } catch (InterruptedException e1) { // TODO Handle InterruptedException throw (RuntimeException) new RuntimeException().initCause(e1); } finally { //restore listeners cancelButton.removeSelectionListener(cancelListener); cancelButton.addSelectionListener(closeListener); cancelButton.setText(IDialogConstants.CLOSE_LABEL); //fix cursors setDisplayCursor(null); cancelButton.setCursor(null); waitCursor.dispose(); waitCursor = null; arrowCursor.dispose(); arrowCursor = null; //enable buttons cancelButton.setEnabled(true); runButton.setEnabled(true); //display response if (progressMonitorPart.isCanceled()) { setMessage("Validation was canceled"); progressMonitorPart.setCanceled(false); } else { int failures = 0; int warnings = 0; if (results != null) { for (int i = 0; i < results.length; i++) { if (results[i] != null) { failures += results[i].failedFeatures.size(); warnings += results[i].warningFeatures.size(); } } } setMessage( "Validation complete, " + failures + " failures and " + warnings + " warnings found."); } focusControl.setFocus(); } } public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } } private class ImportSuiteListener implements SelectionListener { public void widgetSelected(SelectionEvent e) { //determine the file we want to open String fileName = null; //spawn a dialog and choose which file to import Display display = Display.getCurrent(); if (display == null) { // not on the ui thread? display = Display.getDefault(); } FileDialog importDialog = new FileDialog(display.getActiveShell(), SWT.OPEN); //final IPath homepath = Platform.getLocation(); //exportDialog.setFilterPath(homepath.toOSString()); importDialog.setFilterNames( new String[] { Messages.ValidationDialog_filesXML, Messages.ValidationDialog_filesAll }); importDialog.setFilterExtensions(new String[] { "*.xml", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$ boolean done = false; while (!done) { fileName = importDialog.open(); if (fileName == null) { done = true; return; } else { // User has selected a file; see if it already exists File file = new File(fileName); if (!file.exists()) { // The file does not exist; yell at the user and try again MessageBox mb = new MessageBox(importDialog.getParent(), SWT.ICON_ERROR | SWT.OK); mb.setMessage(fileName + Messages.ValidationDialog_fileNotExist); mb.open(); } else { // File exists, so we're good to go done = true; } } } //read the file FileReader reader; try { reader = new FileReader(fileName); } catch (FileNotFoundException e3) { MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.ValidationDialog_fileNotFound, e3.toString()); ValidationPlugin.log(e3.toString()); //log the error, but don't throw the exception return; } TestSuiteDTO newDTO; try { newDTO = XMLReader.readTestSuite(fileName, reader, processor.getPluginDTOs()); } catch (ValidationException e3) { String errorMsg = e3.toString(); MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Exception Occurred", errorMsg); //$NON-NLS-1$ ValidationPlugin.log(errorMsg, e3); return; } try { reader.close(); } catch (IOException e2) { MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Exception Occurred", e2.toString()); //$NON-NLS-1$ ValidationPlugin.log(e2.toString(), e2); return; } //get the existing testSuites Map<String, TestSuiteDTO> suites = processor.getTestSuiteDTOs(); //ensure there is at least one test in the new testSuite if (newDTO.getTests().size() == 0) { //nothing to see here, move along return; } //if no testSuites exist, just copy the new one directly in if (suites.size() == 0) { suites.put(newDTO.getName(), newDTO); defaultTestSuite = newDTO.getName(); //does the testSuite exist? if so, add the new tests to the existing one } else if (suites.containsKey(newDTO.getName())) { //ensure the current testSuite is selected defaultTestSuite = newDTO.getName(); //get the existing testSuite TestSuiteDTO testSuite = (TestSuiteDTO) suites.get(defaultTestSuite); //move the tests to the existing testSuite testSuite = processor.moveTests(testSuite, newDTO.getTests(), false); suites.put(defaultTestSuite, testSuite); //overwrite the suite //a test Suite exists, but it isn't this one; put the new tests into the existing testSuite } else { TestSuiteDTO testSuite = (TestSuiteDTO) suites.get(defaultTestSuite); Map<String, TestDTO> tests = newDTO.getTests(); testSuite = processor.moveTests(testSuite, tests, false); suites.put(defaultTestSuite, testSuite); //overwrite the suite with new map of tests } //do multiple testSuites exist? if so, merge them while (suites.size() > 1) { //find the first testSuite which isn't the defaultTestSuite Object key = null; for (Iterator i = suites.keySet().iterator(); i.hasNext();) { Object thisKey = i.next(); if (!(thisKey.equals(defaultTestSuite))) { key = thisKey; break; } } if (key != null) { TestSuiteDTO alphaSuite = (TestSuiteDTO) suites.get(defaultTestSuite); TestSuiteDTO betaSuite = (TestSuiteDTO) suites.get(key); alphaSuite = processor.moveTests(alphaSuite, betaSuite.getTests(), false); suites.remove(key); //bye betaSuite! suites.put(defaultTestSuite, alphaSuite); //overwrite the suite (alphaSuite has now assimilated betaSuite) } } //all done; save the Map of testSuites and refresh the Tree processor.setTestSuiteDTOs(suites); treeViewer.refresh(); updateButtons(); } public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } } private class ExportSuiteListener implements SelectionListener { public void widgetSelected(SelectionEvent e) { Display display = Display.getCurrent(); if (display == null) { // not on the ui thread? display = Display.getDefault(); } //grab the testSuite we want to save TestSuiteDTO testSuite = (TestSuiteDTO) processor.getTestSuiteDTOs().get(defaultTestSuite); //testSuite is empty? if (testSuite.getTests().size() == 0) { MessageBox mb = new MessageBox(display.getActiveShell(), SWT.ICON_ERROR | SWT.OK); mb.setMessage(Messages.ValidationDialog_noSuitePre + defaultTestSuite + Messages.ValidationDialog_noSuiteSuf); mb.open(); return; } //check the testSuite to ensure that none of the arguments of a test are null if (!DTOUtils.noNullArguments(testSuite)) return; //select the file to export to String fileName = null; //spawn a dialog and choose which file to export to FileDialog exportDialog = new FileDialog(display.getActiveShell(), SWT.SAVE); //final IPath homepath = Platform.getLocation(); //exportDialog.setFilterPath(homepath.toOSString()); exportDialog.setFilterNames( new String[] { Messages.ValidationDialog_filesXML, Messages.ValidationDialog_filesAll }); exportDialog.setFilterExtensions(new String[] { "*.xml", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$ boolean done = false; while (!done) { fileName = exportDialog.open(); if (fileName == null) { done = true; return; } else { // User has selected a file; see if it already exists File file = new File(fileName); if (file.exists()) { // The file already exists; asks for confirmation MessageBox mb = new MessageBox(exportDialog.getParent(), SWT.ICON_WARNING | SWT.YES | SWT.NO); mb.setMessage(fileName + Messages.ValidationDialog_fileExists); // If they click Yes, we're done and we drop out. If // they click No, we redisplay the File Dialog done = mb.open() == SWT.YES; } else { // File does not exist, so we're good to go done = true; } } } //construct a writer Writer writer; try { writer = new FileWriter(fileName, false); } catch (IOException e1) { // TODO Handle IOException throw (RuntimeException) new RuntimeException().initCause(e1); } //write the file XMLWriter.writeTestSuite(testSuite, writer); } public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } } /** * Retrieves the ValidationProcessor object from the blackboard, or null if one does not exist. * * @param map * @return */ private ValidationProcessor loadDialogState(IMap map) { Object currentState = map.getBlackboard().get(BLACKBOARD_KEY); if (currentState instanceof ValidationProcessor) return (ValidationProcessor) currentState; else return null; } /** * Saves the ValidationProcessor object on the blackboard, so we can restore * the state of the validation dialog the next time the dialog is opened. * * @param validationProcessor * @param map */ private void saveDialogState(ValidationProcessor validationProcessor, IMap map) { map.getBlackboard().put(BLACKBOARD_KEY, validationProcessor); } }