Package org.locationtech.udig.catalog.ui

Source Code of org.locationtech.udig.catalog.ui.AbstractResolveContentProvider$Update

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

import java.io.IOException;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;

import org.locationtech.udig.catalog.CatalogPlugin;
import org.locationtech.udig.catalog.ICatalog;
import org.locationtech.udig.catalog.IResolve;
import org.locationtech.udig.catalog.IResolveChangeEvent;
import org.locationtech.udig.catalog.IResolveChangeListener;
import org.locationtech.udig.ui.PlatformGIS;

import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.ui.PlatformUI;


/**
* Provides a threaded Tree content provider for IResolve.
* <p>
* Responsibilities:
* <ul>
* <li>Rooted by a catalog
* <li>Ensure that calls to members are dispatched in a non ui thread
* </ul>
* </p>
*
* @author jgarnett
* @since 0.6.0
*/
public class AbstractResolveContentProvider implements IResolveChangeListener {

    /**
     * Map of threads used to resolve associated IResolves.
     * <p>
     * Waking up the thread will cause the associated IResolve to be refreshed.
     * </p>
     * <p>
     * Here an {@link IdentityHashMap} is used because the containsKey otherwise doesn't look deep
     * enough in the object to correctly deal with multilevel services. 
     * </p>
     */
    Map<IResolve, Thread> threadFarm = new IdentityHashMap<IResolve, Thread>();
    /**
     * Captures parent child relationships.
     * <p>
     * Here an {@link IdentityHashMap} is used because the containsKey otherwise doesn't look deep
     * enough in the object to correctly deal with multilevel services. 
     * </p>
     */
    protected final Map<IResolve, List<IResolve>> structure = new IdentityHashMap<IResolve, List<IResolve>>();
    /**
     * Root of this tree, often a ICatalog.
     */
    protected ICatalog catalog;
    protected List<IResolve> list;
    protected Viewer viewer;

    public AbstractResolveContentProvider() {
        super();
    }

    /**
     * Catalog has changed!
     * <p>
     * Will only start up a thread to update the structure if:
     * <ul>
     * <li>We care about this resolve
     * <li>We are not already running a thread
     * </ul>
     * </p>
     * This will allow us to "ignore" events generated by the process up inspecting the resolve
     * being updated.
     * </p>
     *
     * @param event
     */
    public void changed( IResolveChangeEvent event ) {
      if( threadFarm==null ){
        // we are disposed
        if( catalog!=null ){
          catalog.removeCatalogListener(this);
        }
        return;
      }
        if ( event.getType() != IResolveChangeEvent.Type.POST_CHANGE) {
            return;
        }
        IResolve resolve = event.getResolve();
        if (threadFarm.containsKey(resolve)) {
            update(resolve);
        }
    }

    /**
     * Called by thread to client code to get the content refreshed.
     * <p>
     * This call will not update structure, just appearance.
     * </p>
     *
     * @param resolve
     */
    public void refresh( final IResolve resolve ) {
        if( PlatformUI.getWorkbench().isClosing() )
            return;
        Runnable object = new Runnable(){
          public void run() {
            if (viewer instanceof TreeViewer) {
            TreeViewer treeViewer = (TreeViewer) viewer;
            treeViewer.refresh(resolve, true);
          }else{
              viewer.refresh();
          }
          }
        };
       
        PlatformGIS.asyncInDisplayThread(object, true);
    }

    /**
     * Update appearance and structure.
     * <p>
     * Note: this will spawn a thread to fetch the required information.
     * </p>
     *
     * @param resolve
     */
    public void update( final IResolve resolve ) {
        if (resolve == null) {
            // go away
            return;
        }
        if (resolve.getIdentifier() == null) {
            // go away x 2
            // System.out.println( "Got an resolve with out an id "+ resolve);
        }
        // run the thread, unless it is already running...
        // (this will cause any change events generated by the thread
        // to be ignored).
        if (threadFarm.containsKey(resolve)) {
            Thread update = threadFarm.get(resolve);
            if (update == null) {
                // This IResolve is not suitable for member resolution
                //
            }
            if (update.isAlive()) {
                // thread will already report back to structure
                // Note: thread should end with a async update to the
                // assoicated element
            } else {
                // We had a thread but it stopped - must be do to an error?
                //
                update.interrupt();
               
                update = new Thread(new Update(resolve), "Update " + resolve.getIdentifier()); //$NON-NLS-1$
                threadFarm.put(resolve, update);
                update.setPriority(Thread.MIN_PRIORITY);
                update.start();
            }
        } else {
            // request a structure update
            Thread update = new Thread(new Update(resolve), "Update " + resolve.getIdentifier()); //$NON-NLS-1$
            threadFarm.put(resolve, update);
            update.setPriority(Thread.MIN_PRIORITY);
            update.start();
        }
    }

    /**
     * Notifies this content provider that the given viewer's input has been switched to a different
     * element.
     * <p>
     * A typical use for this method is registering the content provider as a listener to changes on
     * the new input (using model-specific means), and deregistering the viewer from the old input.
     * In response to these change notifications, the content provider should update the viewer (see
     * the add, remove, update and refresh methods on the viewers).
     * </p>
     * <p>
     * The viewer should not be updated during this call, as it might be in the process of being
     * disposed.
     * </p>
     *
     * @param viewer the viewer
     * @param oldInput the old input element, or <code>null</code> if the viewer did not
     *        previously have an input
     * @param newInput the new input element, or <code>null</code> if the viewer does not have an
     *        input
     */
    @SuppressWarnings("unchecked")
    public void inputChanged( Viewer newViewer, Object oldInput, Object newInput ) {
        if (oldInput == newInput) {
            return;
        }
        viewer = newViewer;
        if (catalog != null || list != null) {
            CatalogPlugin.removeListener(this);
        }
        catalog = newInput instanceof ICatalog ? (ICatalog) newInput : null;
        list = newInput instanceof List ? (List<IResolve>) newInput : null;
       
        if (catalog != null || list != null) {
            CatalogPlugin.addListener(this);
        }
    }

    public void dispose() {
        if (threadFarm != null) {
            for( IResolve resolve : threadFarm.keySet() ) {
                Thread thread = threadFarm.get(resolve);
                if (thread!=null && thread.isAlive()) {
                    thread.interrupt();
                }
            }
            if(catalog!=null)
              catalog.removeCatalogListener(this);
           
            CatalogPlugin.getDefault().getLocalCatalog().removeCatalogListener(this);
            threadFarm.clear();
            threadFarm = null;
        }
        if (structure != null) {
            for( IResolve resolve : structure.keySet() ) {
                List<IResolve> children = structure.get(resolve);
                if( children!=null )
                    children.clear();
            }
            structure.clear();
        }
    }


    /**
     * Thread for updating structure
     * <p>
     * Note: thread notify the system that the element has requires an update
     */
    class Update implements Runnable {
        IResolve resolve;
        Update( IResolve target ) {
            resolve = target;
        }
        /**
         * Update strucuture, Thread will be notified if more updates are required.
         * <p>
         * Note: We also need to let ourselves be interrupted
         */
        @SuppressWarnings("unchecked")
        public void run() {
            try {
                try {
                    List<IResolve> members = new ArrayList<IResolve>(resolve.members(null));
                    structure.put(resolve, members);
                } catch (IOException io) {
                    // could not get children
                    // System.out.println( resolve.getIdentifier()+": "+ io );
                    io.printStackTrace();
                    structure.put(resolve, null);
                    // return; // don't even try again
                }
                refresh(resolve);
            } catch (Throwable t) {
                CatalogUIPlugin.trace( resolve.getIdentifier()+": "+t, t );
            }
        }
    }

   
}
TOP

Related Classes of org.locationtech.udig.catalog.ui.AbstractResolveContentProvider$Update

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.