Package org.locationtech.udig.ui.operations

Source Code of org.locationtech.udig.ui.operations.OpAction$SetEnablement

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

import java.lang.reflect.Array;
import java.net.URL;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import org.locationtech.udig.core.AdapterUtil;
import org.locationtech.udig.internal.ui.URLImageDescriptor;
import org.locationtech.udig.internal.ui.UiPlugin;
import org.locationtech.udig.internal.ui.operations.OperationCategory;
import org.locationtech.udig.internal.ui.operations.OperationMenuFactory;
import org.locationtech.udig.ui.internal.Messages;
import org.locationtech.udig.ui.operations.EnablementUtil.EnablesForData;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
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.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;

/**
* Creates an Action that runs an operation in a background thread when triggered.
*
* @author jeichar
* @since 0.3
*/
public class OpAction extends Action implements ISelectionListener {
    IConfigurationElement configElem;
    volatile IStructuredSelection selection;
    private IOp operation;
    private RunJob runJob;
  private String targetClass;
    OperationCategory category;
    String menuPath;
    private OpFilter filter;
    private EnablesForData enablesForData;
    private volatile NullProgressMonitor monitor=new NullProgressMonitor();
    private boolean loadingError;
    private final static Executor executor=Executors.newFixedThreadPool(1);
   
    /**
     * Subclasses must have the same constructor signature as this constructor,
     * {@linkplain OperationMenuFactory} creates OpActions using this
     * constructor.
     *
     * Construct <code>OpAction</code>.
     *
     */
    public OpAction( IConfigurationElement element) {
        this.configElem = element;
        setId(element.getAttribute("id")); //$NON-NLS-1$
        setText(element.getAttribute("name")); //$NON-NLS-1$
        String icon=element.getAttribute("icon"); //$NON-NLS-1$
        if( icon !=null )
          setImageDescriptor(createImageDescriptor(icon, element));
        String tooltip=element.getAttribute("tooltip"); //$NON-NLS-1$
        if( tooltip!=null )
          setToolTipText(tooltip);
        this.targetClass=element.getAttribute("targetClass"); //$NON-NLS-1$
        this.menuPath=element.getAttribute("menuPath"); //$NON-NLS-1$
        this.runJob=new RunJob(getText());
        enablesForData=EnablementUtil.parseEnablesFor(element.getAttribute("enablesFor"), configElem);//$NON-NLS-1$
        filter=EnablementUtil.parseEnablement(element.getNamespaceIdentifier()+"."+element.getName(), element.getChildren("enablement")); //$NON-NLS-1$ //$NON-NLS-2$
    }

    private ImageDescriptor createImageDescriptor( String icon, IConfigurationElement element ) {
        URL url = Platform.getBundle(element.getNamespaceIdentifier()).getEntry(icon);
        return new URLImageDescriptor(url);
    }
   
    public void run() {
        runJob.display = Display.getCurrent();
        runJob.schedule();
    }
   
    public void runWithEvent( Event event ) {
      runJob.display=event.display;
        runJob.schedule();
    }

    IOp getOperation() {
        if (operation == null) {
            try {
                operation = (IOp) configElem.createExecutableExtension("class"); //$NON-NLS-1$
            } catch (CoreException e) {
                UiPlugin.log("Error loading operation implementation", e); //$NON-NLS-1$
                final Display display = Display.getDefault();
                Runnable runnable=new Runnable(){
                    public void run() {
                        setEnabled(false);
                        MessageDialog.openError(display.getActiveShell(), Messages.OpAction_errorTitle, Messages.OpAction_errorMessage);
                    }
                };
                loadingError=true;
                display.asyncExec(runnable);
            }
        }

        return operation;
    }

    class RunJob extends Job{
      Display display;
        /**
         * Construct <code>RunJob</code>.
         *
         * @param name
         */
        public RunJob( String name ) {
            super(name);
//            setUser(true);
        }

        @Override
        public boolean belongsTo( Object family ) {
            return family == OpAction.class;
        }
       
        protected IStatus run( IProgressMonitor monitor ) {
            if ( selection == null ) {
                return new Status(IStatus.CANCEL, UiPlugin.ID, "OpAction", new IllegalArgumentException()); //$NON-NLS-1$
            }
            try {
                Object target;
                if( enablesForData.minHits==1 && enablesForData.exactMatch){
                    try {
                        target=AdapterUtil.instance.adapt(targetClass, selection.getFirstElement(), monitor);
                        if( target==null ){
                            UiPlugin.log("Factory adapting "+selection.getFirstElement().getClass().getName()+" to a "+ //$NON-NLS-1$ //$NON-NLS-2$
                                    targetClass+" is returning null even though it is advertising that it can " + //$NON-NLS-1$
                                            "do the adaptation", null); //$NON-NLS-1$
                            return Status.OK_STATUS;
                        }
                    } catch (Throwable e) {
                        UiPlugin.log( null, e);
                        return Status.OK_STATUS;
                    }
                }else{
                    List<Object> targets=new LinkedList<Object>();
                    for( Iterator<?> iter = selection.iterator(); iter.hasNext(); ) {
                        Object entry = iter.next();
                        try {
                            Object operationTarget = AdapterUtil.instance.adapt(targetClass, entry, monitor);
                            if( operationTarget==null ){
                                UiPlugin.log("Factory adapting "+entry.getClass().getName()+" to a "+ //$NON-NLS-1$ //$NON-NLS-2$
                                        targetClass+" is returning null even though it is advertising that it can " + //$NON-NLS-1$
                                                "do the adaptation", null); //$NON-NLS-1$
                                return Status.OK_STATUS;
                            }else{
                                targets.add(operationTarget);
                            }
                        } catch (Throwable e) {
                            UiPlugin.log( null, e);
                            return Status.OK_STATUS;
                        }
                    }
                    Class<?> targetClass=targets.get(0).getClass();
                    Object[] tmp=(Object[]) Array.newInstance(targetClass, targets.size());
                    if( enablesForData.minHits==1 && enablesForData.exactMatch){
                      target=targets.size() > 0 ? targets.get(0):null;
                    }else{
                      target=targets.toArray(tmp);
                    }

                }
                IOp op = getOperation();
                op.op(display,target, monitor);
            } catch (Throwable e) {
                UiPlugin.log( null, e);
            }
            return Status.OK_STATUS;
        }

    }

  /**
   * Determines whether the current operation can operate on the object.
   * @return true if object can be used as the operation input.
   */
  public boolean isValid(Object obj) {
    return !this.loadingError && AdapterUtil.instance.canAdaptTo(targetClass, obj) && filter.accept(obj);
  }

  /**
   * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
   */
  public void selectionChanged(IWorkbenchPart part, ISelection selection) {
    if (selection instanceof IStructuredSelection) {
            synchronized (this) {
                IStructuredSelection structured = (IStructuredSelection) selection;

                updateEnablement(structured,false);

            }
    }
  }

    /**
     * Updates the enablement status of this action.
     *
     * @param structured the selection to use to determine the enablement.
     * @param executeSynchronous
     */
    public void updateEnablement( IStructuredSelection structured, boolean executeSynchronous ) {
        if( PlatformUI.getWorkbench().isClosing() )
            return;

       
        NullProgressMonitor lastMonitor = monitor;
        monitor= new NullProgressMonitor();
        lastMonitor.setCanceled(true);
       
        SetEnablement enablement=new SetEnablement(structured, monitor, executeSynchronous);
        if( !executeSynchronous ){
            setEnabled(false);
            executor.execute(enablement);
        }else{
            enablement.run();
        }
    }

    public void setCategory( OperationCategory category ) {
        this.category = category;
    }
    public String getMenuPath() {
        return menuPath;
    }
   
    @Override
    public String toString() {
        return getMenuPath()+"/"+getText(); //$NON-NLS-1$
    }
   
    private class SetEnablement implements Runnable{

        private IStructuredSelection structured;
        private IProgressMonitor monitor;
        private boolean execSync;

        public SetEnablement( IStructuredSelection structured, IProgressMonitor monitor, boolean executeSynchronous ) {
            this.structured=structured;
            this.monitor=monitor;
            this.execSync=executeSynchronous;
        }

        public void run( ){
            if( PlatformUI.getWorkbench().isClosing() )
                return;
            boolean enabled=false;
            int hits=0;
           
            for (Iterator<?> iter = structured.iterator(); iter.hasNext();) {
                if( monitor.isCanceled() )
                    return;
                Object obj = iter.next();
                if ( isValid(obj) ){
                    hits++;
                }else{
                    hits=-1;
                    break;
                }
            }

            if( monitor.isCanceled() )
                return;
           
            if(hits>=enablesForData.minHits){
                if( enablesForData.exactMatch && hits==enablesForData.minHits )
                    enabled=true;
                else if( !enablesForData.exactMatch && hits>=enablesForData.minHits)
                    enabled=true;
            }
           
            final boolean finalEnabled=enabled;
            final boolean oldEnabledState=isEnabled();
            Runnable runnable = new Runnable(){
                public void run() {
                    OpAction.this.selection=structured;
                   
                    setEnabled(finalEnabled);
                   
                    if( category!=null && oldEnabledState!=finalEnabled)
                        category.enablementChanged();
                }
            };
            if( execSync ){
                if( Display.getCurrent()!=null ){
                    runnable.run();
                }else{
                    Display.getDefault().syncExec(runnable);
                }
            }else{
                Display.getDefault().asyncExec(runnable);
            }
        }
    }
}
TOP

Related Classes of org.locationtech.udig.ui.operations.OpAction$SetEnablement

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.