edu.ku.brc.specify.tasks.subpane.LocalityMapperSubPane.java Source code

Java tutorial

Introduction

Here is the source code for edu.ku.brc.specify.tasks.subpane.LocalityMapperSubPane.java

Source

/* Copyright (C) 2015, University of Kansas Center for Research
 * 
 * Specify Software Project, specify@ku.edu, Biodiversity Institute,
 * 1345 Jayhawk Boulevard, Lawrence, Kansas, 66045, USA
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package edu.ku.brc.specify.tasks.subpane;

import static edu.ku.brc.ui.UIHelper.createLabel;
import static edu.ku.brc.ui.UIRegistry.getResourceString;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Image;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Formatter;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.commons.lang.StringUtils;
import org.jdesktop.animation.timing.TimingTarget;

import edu.ku.brc.af.core.AppContextMgr;
import edu.ku.brc.af.core.Taskable;
import edu.ku.brc.af.prefs.AppPrefsCache;
import edu.ku.brc.af.tasks.subpane.BaseSubPane;
import edu.ku.brc.af.ui.forms.ControlBarPanel;
import edu.ku.brc.af.ui.forms.FormViewObj;
import edu.ku.brc.af.ui.forms.MultiView;
import edu.ku.brc.af.ui.forms.ResultSetController;
import edu.ku.brc.af.ui.forms.ResultSetControllerListener;
import edu.ku.brc.af.ui.forms.persist.AltViewIFace;
import edu.ku.brc.af.ui.forms.persist.ViewIFace;
import edu.ku.brc.helpers.SwingWorker;
import edu.ku.brc.services.mapping.LocalityMapper;
import edu.ku.brc.specify.datamodel.CollectingEvent;
import edu.ku.brc.specify.datamodel.CollectionObject;
import edu.ku.brc.specify.datamodel.Determination;
import edu.ku.brc.specify.datamodel.Locality;
import edu.ku.brc.specify.datamodel.Taxon;
import edu.ku.brc.specify.extras.FishBaseInfoGetter;
import edu.ku.brc.specify.extras.FishBaseInfoGetterListener;
import edu.ku.brc.specify.tasks.services.CollectingEventLocalityKMLGenerator;
import edu.ku.brc.ui.DateWrapper;
import edu.ku.brc.ui.IconManager;
import edu.ku.brc.ui.ImageDisplay;
import edu.ku.brc.ui.UIRegistry;

/**
 * A default pane for display a simple label telling what it is suppose to do
     
 * @code_status Alpha
 **
 * @author rods
 *
 */
@SuppressWarnings("serial")
public class LocalityMapperSubPane extends BaseSubPane
        implements LocalityMapper.MapperListener, ResultSetControllerListener, TimingTarget {
    //private static final Logger log = Logger.getLogger(SimpleDescPane.class);
    protected DateWrapper scrDateFormat = AppPrefsCache.getDateWrapper("ui", "formatting", "scrdateformat");
    protected static final Cursor handCursor = new Cursor(Cursor.HAND_CURSOR);
    protected static final Cursor defCursor = new Cursor(Cursor.DEFAULT_CURSOR);

    protected LocalityMapper localityMapper = new LocalityMapper();
    protected JLabel imageLabel = createLabel(getResourceString("LoadingImage"));
    protected JLabel titleLabel = createLabel("");
    protected MultiView multiView;

    protected List<CollectingEvent> collectingEvents;
    protected List<Hashtable<String, Object>> valueList = new ArrayList<Hashtable<String, Object>>();
    protected List<Rectangle> markerRects = new ArrayList<Rectangle>();
    protected boolean dirty = false;

    protected List<ImageGetter> imageGetterList = new ArrayList<ImageGetter>();
    protected Hashtable<String, Image> imageMap = new Hashtable<String, Image>();
    protected FormViewObj formViewObj;
    protected JList imageJList;

    protected Hashtable<String, String> imageURLs = new Hashtable<String, String>();

    protected ResultSetController recordSetController;
    protected ControlBarPanel controlPanel;
    protected JButton googleBtn;
    protected CollectingEventLocalityKMLGenerator kmlGen;
    protected List<CollectingEvent> colEvents;
    protected LocalityMapperSubPane thisPane;

    /**
     * The incoming List of Collecting Events is already Sorted by StartDate.
    * @param name the name
     * @param task the owning task
     * @param colEvents sorted list of collecting events
     */
    public LocalityMapperSubPane(final String name, final Taskable task, final List<CollectingEvent> colEvents) {
        super(name, task);

        this.colEvents = colEvents;
        this.thisPane = this;

        progressLabel.setText("Loading Locality Data and Maps...");

        //localityMapper.addTimingTarget(this);

        setBackground(Color.WHITE);

        final SwingWorker worker = new SwingWorker() {
            @Override
            public Object construct() {
                createUI();
                return null;
            }

            //Runs on the event-dispatching thread.
            @Override
            public void finished() {
                thisPane.removeAll();
                setLayout(
                        new LocalityMapperLayoutManager(thisPane, titleLabel, imageLabel, controlPanel, multiView));

                multiView.setData(valueList.get(0));

                validate();
                doLayout();

            }
        };
        worker.start();
    }

    /**
     *
     */
    protected void createUI() {
        kmlGen = new CollectingEventLocalityKMLGenerator();
        this.collectingEvents = new ArrayList<CollectingEvent>();

        CollectingEvent startCE = null;
        CollectingEvent endCE = null;

        Vector<Locality> localities = new Vector<Locality>();
        Vector<String> labels = new Vector<String>();
        for (Object obj : colEvents) {
            CollectingEvent collectingEvent = (CollectingEvent) obj;

            Locality locality = collectingEvent.getLocality();
            if (locality == null || locality.getLatitude1() == null || locality.getLongitude1() == null) {
                continue;
            }

            collectingEvents.add(collectingEvent);
            kmlGen.addDataObj(collectingEvent, "");

            if (collectingEvents.size() == 1) {
                startCE = collectingEvent;
                endCE = collectingEvent;
            }
            // XXX TODO FIX ME!
            if (startCE == null || endCE == null) {
                return;
            }
            // There may be an End Date that is further out than than the End Date of the last item
            // with the latest Start Date
            if (startCE.getStartDate().compareTo(collectingEvent.getStartDate()) > 1) {
                startCE = collectingEvent;
            }
            Calendar leftCal = endCE.getEndDate() != null ? endCE.getEndDate() : endCE.getStartDate();
            Calendar rightCal = collectingEvent.getEndDate() != null ? collectingEvent.getEndDate()
                    : collectingEvent.getStartDate();
            if (leftCal.compareTo(rightCal) < 0) {
                endCE = collectingEvent;
            }

            Hashtable<String, Object> map = new Hashtable<String, Object>();

            Set<CollectionObject> colObjs = collectingEvent.getCollectionObjects();

            map.put("startDate", collectingEvent.getStartDate());
            map.put("endDate", collectingEvent.getEndDate());

            Set<Object> taxonNames = new HashSet<Object>();
            for (CollectionObject co : colObjs) {
                for (Determination d : co.getDeterminations()) {
                    if (d.isCurrentDet()) {
                        //System.out.println(d.getTaxon().getName() + "("+co.getCountAmt()+")");
                        Taxon taxon = d.getPreferredTaxon();
                        if (taxon != null) {
                            taxonNames.add(taxon.getName()
                                    + (co.getCountAmt() != null ? " (" + co.getCountAmt() + ")" : ""));
                            if (taxon.getRankId() == 220) {
                                Taxon genus = taxon.getParent();
                                if (genus.getRankId() == 180) {
                                    ImageGetter imgGetter = new ImageGetter(imageGetterList, imageMap, imageURLs,
                                            genus.getName(), taxon.getName());
                                    imageGetterList.add(imgGetter);
                                }
                            }
                        }
                        break;
                    }
                }
            }
            map.put("taxonItems", taxonNames);

            map.put("latitude1", locality.getLatitude1());
            map.put("longitude1", locality.getLongitude1());

            /*
            Calendar cal = collectingEvent.getStartDate();
            if (cal != null)
            {
              labels.add(scrDateFormat.format(cal.getTime()));
                
            } else if (collectingEvent.getVerbatimDate() != null)
            {
              labels.add(collectingEvent.getVerbatimDate());
                
            } else
            {
              labels.add(Integer.toString(collectingEvent.getCollectingEventId()));
                
            }
            */
            labels.add(Integer.toString(collectingEvents.size()));
            localities.add(locality);
            valueList.add(map);

        }

        // XXX Fix me shouldn't be hard coded here to make it work
        localityMapper.setMaxMapWidth(515);
        localityMapper.setMaxMapHeight(375);

        Color arrow = new Color(220, 220, 220);
        localityMapper.setArrowColor(arrow);
        localityMapper.setDotColor(Color.WHITE);
        localityMapper.setDotSize(4);
        localityMapper.setLabelColor(Color.RED);

        int inx = 0;
        for (Locality locality : localities) {
            localityMapper.addLocationAndLabel(locality, labels != null ? labels.get(inx) : null);
            inx++;
        }
        localityMapper.setCurrentLoc(localities.get(0));
        localityMapper.setCurrentLocColor(Color.RED);

        // XXX DEMO  (Hard Coded 'null' means everyone would have one which may not be true)
        // "null" ViewSet name means it should use the default
        ViewIFace view = AppContextMgr.getInstance().getView("LocalityMapper");

        // TODO WHERE's the ERROR checking !
        multiView = new MultiView(null, null, view, AltViewIFace.CreationMode.VIEW, MultiView.NO_OPTIONS);
        multiView.setBorder(
                BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(new Color(138, 128, 128)),
                        BorderFactory.createEmptyBorder(4, 4, 4, 4)));

        formViewObj = multiView.getCurrentViewAsFormViewObj();
        formViewObj.getUIComponent().setBackground(Color.WHITE);

        imageJList = formViewObj.getCompById("taxonItems");
        imageJList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    String nameStr = (String) imageJList.getSelectedValue();
                    if (nameStr != null) {
                        int index = nameStr.indexOf(" (");
                        if (index > -1) {
                            nameStr = nameStr.substring(0, index);
                        }
                    }

                    //System.out.println("Getting["+name+"]");
                    Image img = null;
                    if (StringUtils.isNotEmpty(nameStr)) {
                        img = imageMap.get(nameStr); // might return null
                        ImageDisplay imgDisplay = formViewObj.getCompById("image");
                        if (img != null) {
                            imgDisplay.setImage(new ImageIcon(img));
                        } else {
                            imgDisplay.setImage((Image) null);
                        }
                    }

                }
            }
        });

        // XXX TODO FIX ME!
        if (startCE == null || endCE == null) {
            return;
        }
        String startDateStr = scrDateFormat.format(startCE.getStartDate().getTime());
        String endDateStr = scrDateFormat
                .format((endCE.getEndDate() != null ? endCE.getEndDate() : endCE.getStartDate()).getTime());

        Formatter formatter = new Formatter();
        titleLabel.setText(formatter
                .format(getResourceString("LocalityMapperTitle"), new Object[] { startDateStr, endDateStr })
                .toString());

        Font font = titleLabel.getFont();
        titleLabel.setFont(new Font(font.getFontName(), Font.BOLD, font.getSize() + 2));

        recordSetController = new ResultSetController(null, false, false, false, null, collectingEvents.size(),
                true);
        recordSetController.addListener(this);
        recordSetController.getPanel().setBackground(Color.WHITE);

        controlPanel = new ControlBarPanel(getBackground());
        controlPanel.add(recordSetController.getPanel());
        controlPanel.setRecordSetController(recordSetController);
        controlPanel.setBackground(Color.WHITE);

        googleBtn = new JButton(IconManager.getIcon("GoogleEarth", IconManager.STD_ICON_SIZE));
        googleBtn.setMargin(new Insets(1, 1, 1, 1));
        googleBtn.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
        googleBtn.setSize(new Dimension(18, 18));
        googleBtn.setPreferredSize(new Dimension(18, 18));
        googleBtn.setMaximumSize(new Dimension(18, 18));
        googleBtn.setFocusable(false);
        googleBtn.setBackground(Color.WHITE);

        controlPanel.addButtons(new JButton[] { googleBtn }, false);

        googleBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                try {
                    UIRegistry.displayStatusBarText("Exporting Collecting Events in KML."); // XXX I18N
                    kmlGen.setSpeciesToImageMapper(imageURLs);
                    kmlGen.outputToFile(System.getProperty("user.home") + File.separator + "specify.kml");

                } catch (Exception ex) {
                    edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(LocalityMapperSubPane.class, ex);
                    ex.printStackTrace();
                }
            }
        });

        addMouseMotionListener(new MouseMotionListener() {
            public void mouseDragged(MouseEvent e) {
                // nothing
            }

            public void mouseMoved(MouseEvent e) {
                checkMouseLocation(e.getPoint(), false);
            }
        });

        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                checkMouseLocation(e.getPoint(), true);
            }

        });

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                getLocalityMap();
            }
        });

    }

    /**
     * Helper for the above Runnable
     */
    protected void getLocalityMap() {
        localityMapper.getMap(this);
    }

    protected void setLabel(final Icon imageIcon) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                imageLabel.setText(null);
                imageLabel.setIcon(imageIcon);
            }
        });

        dirty = true;
    }

    protected void setLabel(final String msg) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                imageLabel.setIcon(null);
                imageLabel.setText(msg);
            }
        });
    }

    /**
     * @param mousePnt
     */
    public void checkMouseLocation(final Point mousePnt, final boolean showInfo) {
        if (dirty) {
            markerRects.clear();
            Point pnt = imageLabel.getLocation();
            //System.out.println("***************** "+pnt+"  "+imageLabel.getBounds()+"  "+imageLabel.getParent()+"  "+this);
            for (Point p : localityMapper.getMarkerLocations()) {
                //System.out.println("*** "+(pnt.x+p.x-5)+"  "+(pnt.y+p.y-5));
                markerRects.add(new Rectangle(pnt.x + p.x - 5, pnt.y + p.y - 5, 10, 10));
            }
            dirty = false;
        }

        int inx = 0;
        for (Rectangle r : markerRects) {
            //System.out.println(mousePnt.x+" "+mousePnt.y+"  "+r);
            if (r.contains(mousePnt)) {
                if (showInfo) {
                    Hashtable<String, Object> map = valueList.get(inx);
                    multiView.setData(map);
                    localityMapper.setCurrentLoc(collectingEvents.get(inx).getLocality());

                } else {
                    setCursor(handCursor);
                }
                return;
            }
            // else
            setCursor(defCursor);
            inx++;
        }
        //multiView.setData(null);

    }

    //------------------------------------------------------------------------
    //-- ResultSetControllerListener
    //------------------------------------------------------------------------

    /* (non-Javadoc)
     * @see edu.ku.brc.ui.forms.ResultSetControllerListener#indexChanged(int)
     */
    public void indexChanged(int newIndex) {
        Hashtable<String, Object> map = valueList.get(newIndex);
        multiView.setData(map);
        localityMapper.setCurrentLoc(collectingEvents.get(newIndex).getLocality());
        repaint();
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.ui.forms.ResultSetControllerListener#indexAboutToChange(int, int)
     */
    public boolean indexAboutToChange(int oldIndex, int newIndex) {
        return true;
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.ui.forms.ResultSetControllerListener#newRecordAdded()
     */
    public void newRecordAdded() {
        // nothing
    }

    //------------------------------------------------------------------------
    //-- Inner Classes
    //------------------------------------------------------------------------

    class ImageGetter implements FishBaseInfoGetterListener {
        protected FishBaseInfoGetter getter;
        protected List<ImageGetter> list;
        protected Hashtable<String, Image> map;
        protected Hashtable<String, String> imageURLMap;
        protected String genus;
        protected String species;

        public ImageGetter(final List<ImageGetter> list, final Hashtable<String, Image> map,
                final Hashtable<String, String> imageURLMap, final String genus, final String species) {
            this.list = list;
            this.map = map;
            this.genus = genus;
            this.species = species;
            this.imageURLMap = imageURLMap;

            getter = new FishBaseInfoGetter(this, FishBaseInfoGetter.InfoType.Thumbnail, genus, species);
            getter.start();
        }

        public void infoArrived(FishBaseInfoGetter getterArg) {
            //System.out.println("["+name+"]["+getter.getImage()+"]");
            if (getterArg.getImage() != null) {
                imageURLMap.put(genus + " " + species, getterArg.getImageURL());
                //System.out.println("["+genus+" "+species+"]["+getter.getImageURL()+"]");
                map.put(species, getterArg.getImage());
            }
            cleanUp();
        }

        public void infoGetWasInError(FishBaseInfoGetter getterArg) {
            cleanUp();
        }

        protected void cleanUp() {
            list.remove(this);
            list = null;
            map = null;
            getter.setConsumer(null);
            getter = null;
        }
    }

    //-----------------------------------------------------------------
    // MapperListener Interface
    //-----------------------------------------------------------------

    public void mapReceived(Icon map) {
        setLabel(map);
    }

    public void exceptionOccurred(Exception e) {
        setLabel("Was unable to get the map.");
    }

    /**
     * The layout manager for laying out NavBoxes in a vertical fashion (only)
     *
     * @author rods
     *
     */
    class LocalityMapperLayoutManager implements LayoutManager {
        protected final int gap = 5;
        protected final LocalityMapperSubPane parent;
        protected final JLabel titleLbl;
        protected final JLabel label;
        protected final JPanel controlBar;
        protected final MultiView form;

        protected Dimension preferredSize = new Dimension(100, 100);

        /**
         * Contructs a layout manager for layting out NavBoxes. It lays out all the NavBoxes vertically
         * and uses the 'ySeparator' as the spacing in between the boxes. It uses borderPadding as a 'margin'
         * aroound all the boxes
         * @param borderPadding the margin around the boxes
         * @param ySeparation the vertical separation inbetween the boxes.
         */
        public LocalityMapperLayoutManager(final LocalityMapperSubPane parent, final JLabel titleLbl,
                final JLabel label, final JPanel controlBar, final MultiView form) {
            this.parent = parent;
            this.label = label;
            this.titleLbl = titleLbl;
            this.controlBar = controlBar;
            this.form = form;

            parent.add(label);
            parent.add(form);
            parent.add(titleLbl);
            parent.add(controlBar);
        }

        /* (non-Javadoc)
         * @see java.awt.LayoutManager#addLayoutComponent(java.lang.String, java.awt.Component)
         */
        public void addLayoutComponent(String arg0, Component arg1) {
            //throw new NullPointerException("In addLayoutComponent");
        }

        /* (non-Javadoc)
         * @see java.awt.LayoutManager#removeLayoutComponent(java.awt.Component)
         */
        public void removeLayoutComponent(Component arg0) {
            //throw new NullPointerException("In removeLayoutComponent");
        }

        /* (non-Javadoc)
         * @see java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
         */
        public Dimension preferredLayoutSize(Container arg0) {
            //Dimension size     = arg0.getSize();
            Dimension formSize = form.getPreferredSize();
            return new Dimension(formSize.width + 200, formSize.height + 200);
        }

        /* (non-Javadoc)
         * @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
         */
        public Dimension minimumLayoutSize(Container arg0) {
            Dimension size = arg0.getPreferredSize();
            Dimension formSize = form.getPreferredSize();

            int w = size.width - formSize.width - (3 * gap);
            int h = size.height - formSize.height - (2 * gap);
            return new Dimension(w, h);
        }

        /* (non-Javadoc)
         * @see java.awt.LayoutManager#layoutContainer(java.awt.Container)
         */
        public void layoutContainer(Container target) {
            synchronized (target.getTreeLock()) {
                Dimension size = target.getSize();
                Dimension formSize = form.getPreferredSize();
                //Dimension labelSize = label.getPreferredSize();

                if (size.width > formSize.width && size.height > formSize.height) {
                    //preferredSize.setSize(size.width - formSize.width - (3 * gap), size.height - formSize.height - (2*gap));
                    preferredSize.setSize(size.width - formSize.width - (3 * gap), formSize.height);
                    //preferredSize.setSize(300, 250); // XXX

                    int formY = (size.height - formSize.height) / 2;
                    form.setLocation((size.width - formSize.width) - gap, formY);
                    //System.out.println("1 formSize: "+formSize);
                    form.setSize(formSize);
                    form.setVisible(true);

                    Dimension compSize = titleLbl.getPreferredSize();
                    titleLbl.setBounds((size.width - compSize.width) / 2, (formY - compSize.height) / 2,
                            compSize.width, compSize.height);

                    //label.setLocation((size.width - (preferredSize.width + (gap * 2))) / 2, (size.height - preferredSize.height)/2);
                    int labelX = gap;
                    int labelY = (size.height - preferredSize.height) / 2;
                    label.setLocation(labelX, labelY);

                    //System.out.println("2 label preferredSize "+preferredSize);
                    label.setSize(preferredSize);
                    localityMapper.setMaxMapWidth(preferredSize.width);
                    localityMapper.setMaxMapHeight(preferredSize.height);

                    // XXXX DEBUG
                    //localityMapper.setPreferredMapWidth(300);
                    //localityMapper.setPreferredMapHeight(250);

                    compSize = controlBar.getPreferredSize();
                    controlBar.setBounds(labelX + (preferredSize.width - compSize.width) / 2,
                            labelY + preferredSize.height + gap, compSize.width, compSize.height);

                } else {
                    preferredSize.setSize(size.width - (2 * gap), size.height - (2 * gap));
                    label.setLocation(0, 0);
                    label.setSize(preferredSize);
                    form.setVisible(false);
                }
            }
        }
    }

    public void begin() {
        // ignore
    }

    public void end() {
        // ignore
    }

    public void repeat() {
        // ignore
    }

    public void timingEvent(float fraction) {
        this.repaint();
    }
}