Package org.locationtech.udig.ui

Source Code of org.locationtech.udig.ui.SearchPart

/* 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.ui;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.locationtech.udig.ui.internal.Messages;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ISetSelectionTarget;
import org.eclipse.ui.part.ViewPart;

/**
* A ViewPart with support for a background "search" process.
* <p>
* The part will automatically show the "progress" when the monitored
* Job(s) are running.
* </p>
* @author jgarnett
* @since 1.0.0
*/
public class SearchPart extends ViewPart implements ISetSelectionTarget {
   
    /** Viewer for search results List/Tree/Table ... */
    protected StructuredViewer viewer; // often a tree or table viewer
       
    /**
     * Used to cancel current searchMonitor
     * <p>
     * Usually available in the toolbar.
     * </p>
     */
    protected IAction cancel;
   
    /**
     * Used to control search jobs.
     * <p>
     * Only one "batch" of search jobs is outstanding at anyone
     * time.
     * </p>
     */
    protected IProgressMonitor searchMonitor;

    protected SashForm splitter;

    /** Save state here */
    protected IMemento save;
    protected Composite parent;
   
    IDialogSettings settings;
   
    /** We need dialog settings for persistence */
    protected SearchPart( IDialogSettings dialogSettings ) {
        settings = dialogSettings;
    }
    @Override
    public void init( IViewSite site, IMemento memento ) throws PartInitException {
        super.init(site, memento);
        save = memento;
    }       
   
    @Override
    public void saveState( IMemento memento ) {
        if ( splitter == null) { // part has not been created
            if (save != null) { //Keep the old state;
                memento.putMemento( save );
            }
            return;
        }       
    }
    private void addResizeListener(Composite parent) {
        parent.addControlListener(new ControlListener() {
            public void controlMoved(ControlEvent e) {
            }
            public void controlResized(ControlEvent e) {
                computeOrientation();
            }
        });
    }
    
    protected enum Orientation { VERTICAL, HORIZONTAL, SINGLE, AUTOMATIC };
    protected Orientation orientation = Orientation.VERTICAL;
   
    void computeOrientation() {
        saveSplitterRatio();
        if( save != null ) save.putInteger("orientation", orientation.ordinal() ); //$NON-NLS-1$
        if ( orientation != Orientation.AUTOMATIC ) {
            setOrientation( orientation );
        }
        else {
            if (orientation == Orientation.SINGLE ) return;
           
            Point size= parent.getSize();
            if (size.x != 0 && size.y != 0) {
                if (size.x > size.y)
                    setOrientation( Orientation.HORIZONTAL );
                else
                    setOrientation( Orientation.VERTICAL );
            }
        }
    }
    private void saveSplitterRatio() {
        if (splitter != null && ! splitter.isDisposed()) {
            int[] weigths = splitter.getWeights();
            int ratio = (weigths[0] * 1000) / (weigths[0] + weigths[1]);
            settings.put( "ratio"+orientation, ratio );             //$NON-NLS-1$
        }
    }
    private void restoreSplitterRatio() {
        try {
            Integer ratio= settings.getInt("ratio"+orientation); //$NON-NLS-1$
            if (ratio == null)
                return;
            splitter.setWeights(new int[] {ratio, 1000 - ratio});
        }
        catch( NumberFormatException nan ) {
            // ignore bad setting
        }
    }
   
    Orientation currentOrientation;
    private boolean showDetails;
    /**
     * called from ToggleOrientationAction (or compute).
     *
     * @param orientation Orientation.HORIZONTAL or Orientation.VERTICAL
     */
    protected void setOrientation(Orientation orientation) {
        if (currentOrientation == orientation) {
            return; // no change needed
        }
        if (viewer != null && !viewer.getControl().isDisposed() &&
            splitter != null && !splitter.isDisposed() ) {
           
            if (orientation == Orientation.SINGLE) {
                setShowDetails(false);
            } else {
                if (currentOrientation == Orientation.SINGLE) {
                    setShowDetails(true);
                }
                boolean horizontal = orientation == Orientation.HORIZONTAL;
                splitter.setOrientation( horizontal ? SWT.HORIZONTAL : SWT.VERTICAL);
            }
            splitter.layout();
        }
        updateCheckedState();

        currentOrientation = orientation;
       
        restoreSplitterRatio();
    }
    private ToggleOrientationAction[] toggleOrientationActions;
    private Composite details;
    private IPartListener2 partListener;
    private void updateCheckedState() {
        for (ToggleOrientationAction toggle : toggleOrientationActions) {
            toggle.setChecked( orientation == toggle.getOrientation());
        }
    }
    public void setShowDetails(boolean show) {
        showDetails = show;
        showOrHideDetails();
    }
    private void showOrHideDetails() {
        if (showDetails) {
            splitter.setMaximizedControl(null);
        } else {
            splitter.setMaximizedControl( viewer.getControl() );
        }
    }
   
    /**
     * Creates the SWT controls for this workbench part.
     * <p>
     * The details (from IWorkbenchPart.createPartControl( Composite ))
     * </p>
     * <p>
     * Multi-step process:
     * <ol>
     * <li>Create one or more controls within the parent.</li>
     * <li>Set the parent layout as needed.</li>
     * <li>Register any global actions with the <code>IActionService</code>.</li>
     * <li>Register any popup menus with the <code>IActionService</code>.</li>
     * <li>Register a selection provider with the <code>ISelectionService</code> (optional).
     * </li>
     * </ol>
     * </p>
     *
     * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
     * @param parent
     */
    public void createPartControl( Composite aParent ) {
        parent= aParent;
        addResizeListener(parent);
       
        // split
        splitter = new SashForm( parent, SWT.HORIZONTAL);
        // TODO: key listener
       
        viewer = createViewer( splitter );
        viewer.setContentProvider( createContentProvider() );
        viewer.setLabelProvider( createLabelProvider() );       
        viewer.addSelectionChangedListener( createSelectionListener() );
        getSite().setSelectionProvider(viewer);
        details = createDetails( splitter );
       
        initDragAndDrop();
       
        makeActions();
        fillViewMenu();
        fillActionBars();
       
        initOrientation();
       
        if (save != null) {
            restoreState( save );
        }
        restoreSplitterRatio();
        addPartListener();
    }
   
    /**
     * You can now restore whatever state you need.
     */
    private void restoreState(IMemento memento) {
        //
    }
    protected void saveViewSettings() {       
        saveSplitterRatio();
        settings.put( "orientation", orientation.ordinal() );         //$NON-NLS-1$
    }
    private void addPartListener() {
        final String ID = getViewSite().getId();
        partListener= new IPartListener2() {
                    public void partActivated(IWorkbenchPartReference partRef) { }
                    public void partBroughtToTop(IWorkbenchPartReference partRef) { }
                    public void partClosed(IWorkbenchPartReference partRef) {
                        if (ID.equals(partRef.getId()))
                            saveViewSettings();
                    }
                    public void partDeactivated(IWorkbenchPartReference partRef) {
                        if (ID.equals(partRef.getId()))
                            saveViewSettings();
                    }
                    public void partOpened(IWorkbenchPartReference partRef) { }
                    public void partHidden(IWorkbenchPartReference partRef) { }
                    public void partVisible(IWorkbenchPartReference partRef) { }
                    public void partInputChanged(IWorkbenchPartReference partRef) { }
                };
        getViewSite().getPage().addPartListener(partListener);
    }
    /**
     * Should do the dialog settings thing here ...
     */
    private void initOrientation() {
        orientation = Orientation.AUTOMATIC;
        if( save != null ) {
            Integer integer = save.getInteger( "orientation" ); //$NON-NLS-1$
            if( integer != null ) {
                orientation = Orientation.values()[ integer ];   
            }           
        }

        // force the update
        currentOrientation = null;
        setOrientation( orientation );
    }
    /**
     * Subclass should override to provide custom details display.
     * <p>
     * Many subclasses use PageBook with page selection based on
     * the selection in the viewer.
     * </p>
     * @param splitter
     * @return Composite to use for details display
     */
    protected Composite createDetails( SashForm splitter ) {
        return new Composite( splitter, SWT.NONE );       
    }
    /**
     * Subclass can override to return its kind of details,
     * example a PageBook.
     *
     * @return
     */
    protected Composite getDetails() {
        return details;
    }   
   
    /**
     * Create viewer (default is a ListViewer please override if you want a Tree or Table Viewer.
     * <p>
     * Note the following will be called after creation:
     * <ul>
     * <li>setContentProvider( createContentProvider() );
     * <li>viewer.setLabelProvider( createLableProvider() );
     * </ul>
     * This allows people who subclass you to do their own thing.
     * </p>   
     * @param page
     * @return
     */
    protected StructuredViewer createViewer( Composite parent ) {
        ListViewer viewer = new ListViewer( parent );
        return viewer;
    }
    /**
     * Default implementation calls showDetail( IStructuredSelection ).
     * <p>
     * Override if you want to do something else.
     */
    protected ISelectionChangedListener createSelectionListener() {
        return new ISelectionChangedListener() {
            public void selectionChanged( SelectionChangedEvent event ) {
                ISelection sel= event.getSelection();
                if( sel instanceof IStructuredSelection ) {
                    IStructuredSelection selection = (IStructuredSelection) sel;
                    showDetail( selection.getFirstElement() );
                }
            }           
        };
    }
    /** Allows subclass to focus the detail on this selection  */
    protected void showDetail( Object selection ) {
        //
    }

    /**
     * Default implementation will work for lists, please overide if
     * you are into the whole tree thing.
     *
     * @return
     */
    protected IStructuredContentProvider createContentProvider() {
        return new IStructuredContentProvider() {
            @SuppressWarnings("unchecked")
            public Object[] getElements( Object inputElement ) {
                if( inputElement instanceof List ) {
                    return ((List)inputElement).toArray();
                }
                return null;
            }
            public void dispose() {
            }
            public void inputChanged( Viewer viewer, Object oldInput, Object newInput ) {
                assert( newInput instanceof List );
                // lists don't have events for us to watch
            }           
        };
    }

    /**
     * LabelProvider; override to take charge of your labels and icons.
     *
     * @return LabelProvider for use with the viewer
     */
    protected IBaseLabelProvider createLabelProvider() {
        return new LabelProvider();
    }

    /** Will cancel any outstanding search */
    synchronized void stopSearch(){       
        if( searchMonitor != null ){
            IProgressMonitor cancelMonitor = searchMonitor;
           
            searchMonitor = null;
            cancelMonitor.setCanceled( true );           
        }       
    }
       
    /**
     * Subclass should override to support DnD.
     */
    protected void initDragAndDrop() {
        //
    }   

    protected void makeActions() {
        cancel = new Action() {
            public void run() {
                stopSearch();
                setEnabled(false);
                //book.showPage( promptPage );               
            }
        };
        Messages.initAction( cancel, "cancel" ); //$NON-NLS-1$
        cancel.setEnabled( false );
       
        toggleOrientationActions = new ToggleOrientationAction[] {
                new ToggleOrientationAction(this, Orientation.VERTICAL),
                new ToggleOrientationAction(this, Orientation.HORIZONTAL),
                new ToggleOrientationAction(this, Orientation.AUTOMATIC),
                new ToggleOrientationAction(this, Orientation.SINGLE)
            };
       
    }
    /**
    *
    */
   protected void fillViewMenu() {
       IActionBars actionBars = getViewSite().getActionBars();
       IMenuManager viewMenu = actionBars.getMenuManager();
      
       viewMenu.add( cancel );
       viewMenu.add(new Separator());
       for (ToggleOrientationAction toggle : toggleOrientationActions) {
           viewMenu.add( toggle );
       }
   }   
   
    /**
     * Create toolbar with cancel.
     */
    protected void fillActionBars() {
        IActionBars actionBars = getViewSite().getActionBars();
        IToolBarManager toolBar = actionBars.getToolBarManager();

        toolBar.add( cancel );
    }
   
    public void quick( String pattern ) {
        // search through existing contents based on label?
    }

    Object filter = null;
    Job looking = new Job( getPartName()+"..."){ //$NON-NLS-1$
        protected IStatus run( IProgressMonitor monitor ) {
            try {                   
                final ResultSet set=new ResultSet(SearchPart.this);
                Display.getDefault().asyncExec(new Runnable(){
                    public void run() {
                        viewer.setInput( set.results );
                    }
                });
               
                searchImplementation( filter, monitor, set);
               
//                PlatformGIS.runBlockingOperation(new IRunnableWithProgress(){
//
//                    public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException {
//                        searchImplementation( filter, monitor, set);
//                    }
//                   
//                }, monitor);
               
                Display.getDefault().asyncExec(new Runnable(){
                    public void run() {
                        viewer.setSelection(getSelection(set.results), showSelection());
                    }
                });
            }
           
            catch (Throwable t ) {
                //book.showPage( promptPage );                   
            }finally{
                cancel.setEnabled( false );                   
            }
            return Status.OK_STATUS;               
        }
    };
   
    /**
     * Called each time data is added to the result set by the search.  Note: Many items or a single item could have been added.
     *
     * @param set the results of the search at the current point.
     * @param newObjects the objects that have been added this time.
     */
    protected void notifyChange( final ResultSet set, final Collection< ? extends Object> newObjects ) {
        Display.getDefault().asyncExec(new Runnable(){
            public void run() {
                if( !newObjects.isEmpty() )
                    viewer.refresh(true);
            }
        });
    }

    /**
     * Called to determine what object(s) in the input should be the selection in the viewer.  This method is called when the search is complete.
     * The default selection is the first object in the list.
     *
     * @param the complete list of objects in the viewer.
     *
     * @return the selection that will be set in the viewer.  may be null.
     */
    protected ISelection getSelection(List<Object> input) {
        if( input.size()>0 )
            return new StructuredSelection(input.get(0));
        else
            return new StructuredSelection();
    }
    /**
     * Returns true if the selection returned by {@link #getNewSelection(List)} should be shown in the viewer.
     *
     * @return true if the selection returned by {@link #getNewSelection(List)} should be shown in the viewer.
     */
    protected boolean showSelection() {
        return true;
    }

   
    /**
     * Search the catalog for text and update view contents
     *
     * @param pattern
     */
    public void search( final Object newFilter ) {       
        if ( newFilter== null) {
            stopSearch();    
            //book.showPage( promptPage );
            return;
        }       
        stopSearch();
       
        viewer.setInput( null );
        filter = newFilter;       
        searchMonitor=Platform.getJobManager().createProgressGroup();
        searchMonitor.setTaskName( getPartName());          
        looking.setPriority( Job.BUILD );
        looking.setProgressGroup( searchMonitor, IProgressMonitor.UNKNOWN );
        cancel.setEnabled( true );
        looking.schedule(); // do it               
    }
 
    protected void searchImplementation( Object filter, IProgressMonitor monitor, ResultSet results ) {
        // No default action.
     }
   
    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.part.ISetSelectionTarget#selectReveal(org.eclipse.jface.viewers.ISelection)
     */
    public void selectReveal( ISelection selection ) {
        //viewer.setSelection(selection);
    }

    @Override
    public void setFocus() {
        if( viewer != null && viewer.getControl().isVisible() ) {
            viewer.getControl().setFocus();
        }
    }
   
    /**
     * Toggles the orientationof the layout
     */
    static class ToggleOrientationAction extends Action {
        private SearchPart view;   
        private Orientation orientation;       
        public ToggleOrientationAction(SearchPart searchPart, Orientation orientation) {
            super("", AS_RADIO_BUTTON); //$NON-NLS-1$           
            Messages.initAction( this, "orientation_"+orientation.toString().toLowerCase() );             //$NON-NLS-1$
            view = searchPart;
            this.orientation = orientation;
            //PlatformUI.getWorkbench().getHelpSystem().setHelp(this, lookup context id? );                   
        }       
        public Orientation getOrientation() {
            return orientation;
        }          
        /*
         * @see Action#actionPerformed
         */    
        public void run() {
            if (isChecked()) {
                view.orientation = orientation;
                view.computeOrientation();
            }
        }
       
    }
    /**
     * Set of results collected for display in a SearchPart (such as the info view)
     */
    public static class ResultSet{
        SearchPart owner;
        List<Object> results=new CopyOnWriteArrayList<Object>();
        private int changes=0;
       
        private ResultSet(SearchPart owner){
            this.owner=owner;
        }
        public boolean firstNotification() {
            return changes==1;
        }
        private void notifyChange(Collection< ? extends Object> changed){
            changes++;
            owner.notifyChange(this, changed);
        }
        public void add( int arg0, Object arg1 ) {
            results.add(arg0, arg1);
            notifyChange(Collections.singleton(arg1));
        }
        public boolean add( Object arg0 ) {
            boolean add = results.add(arg0);
            notifyChange(Collections.singleton(arg0));
            return add;
        }
        public boolean addAll( Collection< ? extends Object> arg0 ) {
            boolean addAll = results.addAll(arg0);
            notifyChange(arg0);
            return addAll;
        }
        public boolean addAll( int arg0, Collection< ? extends Object> arg1 ) {
            boolean addAll = results.addAll(arg0, arg1);
            notifyChange(arg1);
            return addAll;
        }
        public boolean contains( Object arg0 ) {
            return results.contains(arg0);
        }
        public boolean containsAll( Collection< ? > arg0 ) {
            return results.containsAll(arg0);
        }
        public Object get( int arg0 ) {
            return results.get(arg0);
        }
        public int indexOf( Object arg0 ) {
            return results.indexOf(arg0);
        }
       
    }

}
TOP

Related Classes of org.locationtech.udig.ui.SearchPart

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.