Package org.locationtech.udig.project.ui.controls

Source Code of org.locationtech.udig.project.ui.controls.FeatureTableControl$FeatureTableProvider

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2012, 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.project.ui.controls;

import java.util.ArrayList;
import java.util.List;

import org.locationtech.udig.project.ui.internal.ProjectUIPlugin;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.part.PageBook;
import org.geotools.data.DataUtilities;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.SchemaException;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;

/**
* A TreeViewer control for viewing a table of SimpleFeature attributes.
* <p>
* This object can be created in two ways. The first is using a FeatureReader. This method reads in
* Features a page at a time and populates the table entries. The page size can be set by calling
* FeatureTableControl#setPageSize(int).
* </p>
* <p>
* The second way is using a DefaultFeatureCollection. In this case the control hangs on to a
* reference to the DefaultFeatureCollection and populates the table entries directory from it. This
* method results in a single page containing all features.
* </p>
* TODO: Create next and first action
*
* @author jdeolive
* @since 0.3
*/
public class FeatureTableControl {

    /** results per page * */
    private int pageSize = 10; // XXX: actual put this as a user pref

    /** feature types and reader to get the actual feature data * */
    private FeatureIterator<SimpleFeature> fReader;
    SimpleFeatureType fType;

    /** feature collection for holding features in memory * */
    private List<SimpleFeature> features;

    /** table viewer control * */
    private TableViewer tableViewer;
    private Table table;

    private FeatureCollection<SimpleFeatureType, SimpleFeature> results;

    private PageBook control;

    /**
     * Construct <code>FeatureTableControl</code>.
     * <p>
     * Must call setFeatures before use.
     * </p>
     */
    public FeatureTableControl() {
        clear();
    }
    /**
     * Construct <code>FeatureTableControl</code>.
     *
     * @param features The DefaultFeatureCollection containing the features to be displayed.
     */
    public FeatureTableControl( DefaultFeatureCollection features ) {
        setFeatures(features);
    }

    /**
     * Construct a <code>FeatureTableControl</code>.
     *
     * @param fReader The FeatureReader that returns the actual features.
     */
    public FeatureTableControl( FeatureIterator<SimpleFeature> fReader ) {
        this(fReader, 10);
    }

    /**
     * Construct a <code>FeatureTableControl</code>.
     *
     * @param fReader The FeatureReader that returns the actual features.
     * @param resPerPage Results per page to be shown in the table.
     */
    public FeatureTableControl( FeatureIterator<SimpleFeature> fReader, int resPerPage ) {
        this.fType = null; //fReader.getFeatureType();
        this.fReader = fReader;
        this.pageSize = resPerPage;

        features = new ArrayList<SimpleFeature>();

        // /features = (DefaultFeatureCollection) DefaultFeatureCollections.newCollection();

        // initial page
        next();
    }

    /**
     * Sets the number of features viewed in the table per page.
     *
     * @param resPerPage positive integer.
     */
    public void setPageSize( int resPerPage ) {
        this.pageSize = resPerPage;
    }

    /**
     * Returns the number of features viewed in the table per page.
     *
     * @return positive integer.
     */
    public int getPageSize() {
        return pageSize;
    }

    /**
     * Returns the control representing the table control.
     *
     * @return The internal table viewer control.
     * @see Control
     */
    public Control getControl() {
        return control;
    }

    /**
     * Creates the table control.
     *
     * @param parent The to be parent of the control.
     * @see Composite
     */
    public void createTableControl( Composite parent ) {
        control = new PageBook(parent, SWT.NONE);
        createTableViewer(control);
    }

    /**
     * Moves the control to the next page of features. This method should only be called if the
     * control was created from a <code>org.geotools.data.FeatureReader</code>.
     */
    public void next() {
        // if the control was created directory from a feature collection
        // fReader will be null
        // TODO: Throw an exception here instead ??
        if (fReader != null) {
            nextInternal();
        }
    }

    /**
     * Moves the control to the next page of features.
     */
    protected void nextInternal() {

        // clear the current features
        features.clear();

        try {
            // read in the new features
            for( int i = 0; i < pageSize && fReader.hasNext(); i++ ) {
                features.add(fReader.next());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Updates the table control with the current set of features.
     * <p>
     * This method will ensure that the column information gets updated
     * </p>
     */
    public void update() {
        // System.out.println("Page size:" + pageSize);
        updateTable();
        tableViewer.setInput(features);
    }

    /**
     * Updates the table by adding/removing columns. TableViewer doesn't support updating columns
     * based on the data set supplied so this is a way around it that works nicely.
     */
    protected void updateTable() {
        table = tableViewer.getTable();
        TableColumn tableColumn;

        // aa: For some reason this column is hard coded in here??!!
        // if it's removed, all the loops should be rechecked to remove the +/- 1
        if (table.getColumnCount() > 0) {
            tableColumn = table.getColumn(0);
        } else {
            tableColumn = new TableColumn(table, SWT.CENTER | SWT.BORDER);
        }
        tableColumn.setText("FID"); //$NON-NLS-1$
        tableColumn.setWidth(100);

        if (fType != null) {
            for( int i = 0; i < fType.getAttributeCount(); i++ ) {
                AttributeDescriptor aType = fType.getDescriptor(i);
                if (table.getColumnCount() > i + 1) {
                    tableColumn = table.getColumn(i + 1);
                } else {
                    tableColumn = new TableColumn(table, SWT.CENTER | SWT.BORDER);
                }

                tableColumn.setText(aType.getLocalName());

                tableColumn.setWidth(100);
            }
            for( int i = fType.getAttributeCount() + 1; i < table.getColumnCount(); i++ ) {
                tableColumn = table.getColumn(i);
                tableColumn.dispose();
            }
        }
    }

    /**
     * Creates the table control itself.
     *
     * @param parent Makes A TableViewer which diplays the features.
     * @see Composite
     */
    protected void createTableViewer( Composite parent ) {
        int style = SWT.MULTI; // | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL;
        table = new Table(parent, style);
        // TableColumn tableColumn = new TableColumn(table, SWT.CENTER | SWT.BORDER);
        // tableColumn.setText("FID"); //$NON-NLS-1$
        // tableColumn.setWidth(100);
        //
        // for( int i = 0; i < fType.getAttributeCount(); i++ ) {
        // AttributeDescriptor aType = fType.getAttribute(i);
        // tableColumn = new TableColumn(table, SWT.CENTER | SWT.BORDER);
        // if (aType.isGeometry()) {
        // // jg: wot is this maddness? jd: paul said so
        // tableColumn.setText("GEOMETRY"); //$NON-NLS-1$
        // } else {
        // tableColumn.setText(aType.getName());
        // }
        // tableColumn.setWidth(100);
        // }
        table.setHeaderVisible(true);

        FeatureTableProvider ftp = new FeatureTableProvider();
        tableViewer = new TableViewer(table);
        tableViewer.setContentProvider(ftp);
        tableViewer.setLabelProvider(ftp);
        tableViewer.setInput(features);
        control.showPage(tableViewer.getControl());
        updateTable();

        // tableViewer.refresh();
        // tableViewer.getControl().redraw();
        // tableViewer.getControl().update();
    }

    /**
     * The TableViewer used is returned... would be used for adding listeners and various other
     * things to the tableViewer
     *
     * @return TableViewer
     */
    public TableViewer getTableViewer() {
        return tableViewer;
    }

    /**
     * API use?
     *
     * @author jdeolive
     * @see LabelProvider
     * @see ITableLabelProvider
     * @see IStructuredContentProvider
     */
    class FeatureTableProvider extends LabelProvider
            implements
                ITableLabelProvider,
                IStructuredContentProvider {

        /**
         * Returns the elemetns for the viewer. Input to this method should be at type of
         * <code>org.geotools.feature.DefaultFeatureCollection</code>
         *
         * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
         * @param inputElement A <code>org.geotools.feature.DefaultFeatureCollection.</code>
         * @return An array of <code>org.geotools.feature.SimpleFeature</code>
         * @throws ClassCastException when inputElement not DefaultFeatureCollection
         */
        public Object[] getElements( Object inputElement ) throws ClassCastException {
            @SuppressWarnings("unchecked")
            List<SimpleFeature> features = (List<SimpleFeature>) inputElement;
            return features.toArray();
        }

        /**
         * Does nothing.
         *
         * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
         *      java.lang.Object, java.lang.Object)
         * @param viewer
         * @param oldInput
         * @param newInput
         */
        public void inputChanged( Viewer viewer, Object oldInput, Object newInput ) {
            // do nothing.
            ((TableViewer) viewer).getTable().layout();
        }

        /**
         * Does nothing.
         *
         * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
         * @param element
         * @param columnIndex
         * @return null
         */
        public Image getColumnImage( Object element, int columnIndex ) {
            return null;
        }

        /**
         * Returns the value of the column / feature attribute.
         *
         * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
         * @param element the array of feature attributes.
         * @param columnIndex the column index / feature attribute.
         * @return the string representation of the feature attribute, except for attributes of type
         *         Geometry in which a string representing the type of Geometry is returned.
         * @throws ClassCastException when element not SimpleFeature
         */
        public String getColumnText( Object element, int columnIndex ) throws ClassCastException {
            SimpleFeature f = (SimpleFeature) element;
            if (f == null) {
                ProjectUIPlugin.trace(getClass(), "SimpleFeature was null in FeatureTableControl", (Exception)null); //$NON-NLS-1$
                return null;
            }
            if (columnIndex == 0)
                return f.getID();

            if (columnIndex >= fType.getAttributeCount()) {
                return null;
            }
            AttributeDescriptor at = fType.getDescriptor(columnIndex - 1);
            if (at == null)
                return null;
            if ( at instanceof GeometryDescriptor ) {
                String s = f.getAttribute(columnIndex - 1).getClass().getName();
                return s.substring(s.lastIndexOf('.') + 1);
            }
            if (f.getAttribute(columnIndex - 1) == null)
                return null;
            return f.getAttribute(columnIndex - 1).toString();

        }
    }

    /**
     * Does nothing.
     *
     * @see org.eclipse.ui.IWorkbenchPart#setFocus()
     */
    public void setFocus() {
        // do nothing.
    }
    /**
     * Contents of the current page of features
     *
     * @return DefaultFeatureCollection
     * @see DefaultFeatureCollection
     */
    public List<SimpleFeature> getFeatures() {
        return features;
    }
    /**
     * Set up for a one time only paged access
     *
     * @param reader
     * @see Featurereader API should this throw exceptions? the answer also potentially propagates
     *      the issue and the question ... API is there a memory issue here?
     */
    public void setFeatures( FeatureIterator<SimpleFeature> reader ) {
        this.fReader = reader;
        this.fType = null; //reader.getFeatureType();
        features = new ArrayList<SimpleFeature>();
        next(); // load the first page into the collection
        update();
    }
    /**
     * Set up for a single page of content
     *
     * @param features
     * @see DefaultFeatureCollection
     */
    public void setFeatures( List<SimpleFeature> features ) {
        this.features = features;
        if (features.size() != 0) {
            this.fType = features.get(0).getFeatureType();
        } else {
            this.fType = null;
        }
        // this.pageSize = features.size();
        this.fReader = null;
        update();
    }
    /**
     * Set up for pages access with a next and a reset button. API should this throw exceptions? the
     * answer also potentially propagates the issue and the question ... API is there a memory issue
     * here?
     *
     * @param results
     * @see FeatureResults
     */
    public void setFeatures( FeatureCollection<SimpleFeatureType, SimpleFeature> results ) {
        this.results = results;
        reset();
        update();
    }
    /** Reset to start of FeatureResutls */
    public void reset() {
        int count = pageSize + 1;
        count = results.size();       
        if (count < this.pageSize) {
            List<SimpleFeature> list = DataUtilities.list(results);
            setFeatures(list);           
        } else {
            setFeatures(results.features());           
        }
    }
    /**
     * Don't display nothing :-)
     */
    public void clear() {
        features = new ArrayList<SimpleFeature>();
        try {
            fType = DataUtilities.createType("empty", "message:String"); //$NON-NLS-1$ //$NON-NLS-2$
        } catch (SchemaException e) {
            // TODO Catch e
        }
        fReader = null;
        this.results = null;
    }
}
TOP

Related Classes of org.locationtech.udig.project.ui.controls.FeatureTableControl$FeatureTableProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.