au.org.ala.delta.intkey.ui.TaxonInformationDialog.java Source code

Java tutorial

Introduction

Here is the source code for au.org.ala.delta.intkey.ui.TaxonInformationDialog.java

Source

/*******************************************************************************
 * Copyright (C) 2011 Atlas of Living Australia
 * All Rights Reserved.
 * 
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 ******************************************************************************/
package au.org.ala.delta.intkey.ui;

import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ActionMap;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.event.MouseInputAdapter;

import org.apache.commons.lang.StringUtils;
import org.jdesktop.application.Action;
import org.jdesktop.application.Application;
import org.jdesktop.application.Resource;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;

import au.org.ala.delta.intkey.model.IntkeyContext;
import au.org.ala.delta.model.Item;
import au.org.ala.delta.model.ResourceSettings;
import au.org.ala.delta.model.format.Formatter;
import au.org.ala.delta.model.format.Formatter.AngleBracketHandlingMode;
import au.org.ala.delta.model.format.Formatter.CommentStrippingMode;
import au.org.ala.delta.model.format.ItemFormatter;
import au.org.ala.delta.model.image.Image;
import au.org.ala.delta.model.image.ImageSettings;
import au.org.ala.delta.util.Pair;

public class TaxonInformationDialog extends IntkeyDialog {

    /**
     * 
     */
    private static final long serialVersionUID = -369093284637981457L;

    private List<Item> _taxa;
    private List<Item> _taxaWithImages;

    private int _selectedIndex;
    private ItemFormatter _itemFormatter;
    private Formatter _imageDescriptionFormatter;
    private JPanel _mainPanel;
    private JPanel _comboPanel;
    private JComboBox _comboBox;
    private JPanel _btnPanel;
    private JButton _btnDisplay;
    private JButton _btnMultipleImages;
    private JButton _btnDeselectAll;
    private JButton _btnDone;
    private JPanel _pnlCenter;
    private JPanel _pnlNavigationButtons;
    private JButton _btnStart;
    private JButton _btnPrevious;
    private JButton _btnForward;
    private JButton _btnEnd;
    private JPanel _pnlLists;
    private JPanel _pnlListOther;
    private JScrollPane _sclPnOther;
    private JList _listOther;
    private JLabel _lblOther;
    private JPanel _pnlListIllustrations;
    private JLabel _lblIllustrations;
    private JScrollPane _sclPnIllustrations;
    private JList _listIllustrations;

    private IntkeyContext _context;
    private ResourceSettings _infoSettings;
    private ImageSettings _imageSettings;

    private List<Image> _images;
    private List<Pair<String, String>> _definedDirectiveCommands;

    private List<InformationDialogCommand> _cmds;

    private boolean _imageDisplayEnabled;

    /**
     * Calls Desktop.getDesktop on a background thread as it's slow to
     * initialise
     */
    private SwingWorker<Desktop, Void> _desktopWorker;

    @Resource
    String noImagesCaption;

    @Resource
    String fullDescriptionCaption;

    @Resource
    String title;

    private JButton _btnWebSearch;

    public TaxonInformationDialog(Frame owner, List<Item> taxa, IntkeyContext context,
            boolean imageDisplayEnabled) {
        super(owner, false);

        setPreferredSize(new Dimension(550, 280));
        setMinimumSize(new Dimension(550, 280));

        ResourceMap resourceMap = Application.getInstance().getContext()
                .getResourceMap(TaxonInformationDialog.class);
        resourceMap.injectFields(this);
        ActionMap actionMap = Application.getInstance().getContext().getActionMap(TaxonInformationDialog.class,
                this);

        setTitle(title);
        getContentPane().setLayout(new BorderLayout(0, 0));

        _mainPanel = new JPanel();
        getContentPane().add(_mainPanel, BorderLayout.CENTER);
        _mainPanel.setLayout(new BorderLayout(0, 0));

        _comboPanel = new JPanel();
        _comboPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
        _mainPanel.add(_comboPanel, BorderLayout.NORTH);
        _comboPanel.setLayout(new BorderLayout(0, 0));

        _comboBox = new JComboBox();
        _comboBox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                displayTaxon(_comboBox.getSelectedIndex());
            }
        });

        _comboPanel.add(_comboBox, BorderLayout.CENTER);

        _btnPanel = new JPanel();
        _btnPanel.setBorder(new EmptyBorder(0, 0, 10, 0));
        _mainPanel.add(_btnPanel, BorderLayout.SOUTH);

        _btnDisplay = new JButton();
        _btnDisplay.setAction(actionMap.get("displaySelectedTaxonInformation"));
        _btnPanel.add(_btnDisplay);

        _btnMultipleImages = new JButton();
        _btnMultipleImages.setAction(actionMap.get("displayMultipleImages"));
        _btnMultipleImages.setEnabled(!context.displayContinuous() && imageDisplayEnabled);
        _btnPanel.add(_btnMultipleImages);

        _btnWebSearch = new JButton();
        _btnWebSearch.setAction(actionMap.get("webSearch"));
        _btnWebSearch.setEnabled(true);
        _btnPanel.add(_btnWebSearch);

        _btnDeselectAll = new JButton();
        _btnDeselectAll.setAction(actionMap.get("deselectAllTaxonInformation"));
        _btnPanel.add(_btnDeselectAll);

        _btnDone = new JButton();
        _btnDone.setAction(actionMap.get("done"));
        _btnPanel.add(_btnDone);

        _pnlCenter = new JPanel();
        _mainPanel.add(_pnlCenter, BorderLayout.CENTER);
        _pnlCenter.setLayout(new BorderLayout(0, 0));

        _pnlNavigationButtons = new JPanel();
        _pnlCenter.add(_pnlNavigationButtons, BorderLayout.NORTH);

        _btnStart = new JButton();
        _btnStart.setAction(actionMap.get("firstTaxon"));
        _pnlNavigationButtons.add(_btnStart);

        _btnPrevious = new JButton();
        _btnPrevious.setAction(actionMap.get("previousTaxon"));
        _pnlNavigationButtons.add(_btnPrevious);

        _btnForward = new JButton();
        _btnForward.setAction(actionMap.get("nextTaxon"));
        _pnlNavigationButtons.add(_btnForward);

        _btnEnd = new JButton();
        _btnEnd.setAction(actionMap.get("lastTaxon"));
        _pnlNavigationButtons.add(_btnEnd);

        _pnlLists = new JPanel();
        _pnlCenter.add(_pnlLists, BorderLayout.CENTER);
        _pnlLists.setLayout(new GridLayout(0, 2, 0, 0));

        _pnlListOther = new JPanel();
        _pnlListOther.setBorder(new EmptyBorder(5, 5, 5, 5));
        _pnlLists.add(_pnlListOther);
        _pnlListOther.setLayout(new BorderLayout(0, 0));

        _listOther = new JList();
        _listOther.addMouseListener(new MouseInputAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() >= 2) {
                    int selectedIndex = _listOther.getSelectedIndex();
                    _cmds.get(selectedIndex).execute();
                }
            }

        });

        _sclPnOther = new JScrollPane();
        _sclPnOther.setViewportView(_listOther);
        _pnlListOther.add(_sclPnOther, BorderLayout.CENTER);

        _lblOther = new JLabel();
        _pnlListOther.add(_lblOther, BorderLayout.NORTH);

        _pnlListIllustrations = new JPanel();
        _pnlListIllustrations.setBorder(new EmptyBorder(5, 5, 5, 5));
        _pnlLists.add(_pnlListIllustrations);
        _pnlListIllustrations.setLayout(new BorderLayout(0, 0));

        _lblIllustrations = new JLabel();
        _pnlListIllustrations.add(_lblIllustrations, BorderLayout.NORTH);

        _listIllustrations = new JList();
        _listIllustrations.addMouseListener(new MouseInputAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() >= 2) {
                    if (_imageDisplayEnabled) {
                        int selectedListIndex = _listIllustrations.getSelectedIndex();
                        displaySelectedTaxonImage(selectedListIndex, true);
                    } else {
                        _context.getUI()
                                .displayErrorMessage(UIUtils.getResourceString("ImageDisplayDisabled.error"));
                    }
                }
            }

        });

        _sclPnIllustrations = new JScrollPane();

        _sclPnIllustrations.setViewportView(_listIllustrations);
        _pnlListIllustrations.add(_sclPnIllustrations);

        _context = context;
        _imageDisplayEnabled = imageDisplayEnabled;
        _definedDirectiveCommands = _context.getTaxonInformationDialogCommands();

        _infoSettings = _context.getInfoSettings();
        _imageSettings = _context.getImageSettings();
        _itemFormatter = new ItemFormatter(_context.displayNumbering(), CommentStrippingMode.RETAIN,
                AngleBracketHandlingMode.REMOVE, true, false, false);
        _imageDescriptionFormatter = new Formatter(CommentStrippingMode.RETAIN, AngleBracketHandlingMode.RETAIN,
                true, false);

        int totalNumberImages = 0;
        _taxa = taxa;
        _taxaWithImages = new ArrayList<Item>();
        for (Item taxon : taxa) {
            totalNumberImages += taxon.getImageCount();
            if (taxon.getImageCount() > 0) {
                _taxaWithImages.add(taxon);
            }
        }

        if (totalNumberImages < 2) {
            _btnMultipleImages.setEnabled(false);
        }

        initialize();

        loadDesktopInBackground();

        this.pack();
    }

    private void initialize() {
        // fill combobox with taxa names

        DefaultComboBoxModel comboModel = new DefaultComboBoxModel();
        for (Item taxon : _taxa) {
            String formattedItemName = _itemFormatter.formatItemDescription(taxon);
            formattedItemName = formattedItemName.replace("<", "");
            formattedItemName = formattedItemName.replace(">", "");
            comboModel.addElement(formattedItemName);
        }
        _comboBox.setModel(comboModel);

        displayTaxon(0);
    }

    /**
     * We do this because Desktop.getDesktop() can be very slow
     */
    private void loadDesktopInBackground() {
        _desktopWorker = new SwingWorker<Desktop, Void>() {

            protected Desktop doInBackground() {
                if (Desktop.isDesktopSupported()) {
                    return Desktop.getDesktop();
                } else {
                    return null;
                }
            }
        };
        _desktopWorker.execute();
    }

    private void displayTaxon(int index) {
        _selectedIndex = index;
        Item selectedTaxon = _taxa.get(_selectedIndex);

        _comboBox.setSelectedIndex(_selectedIndex);

        // Update other list
        // _fileNames = new ArrayList<String>();
        _cmds = new ArrayList<InformationDialogCommand>();
        DefaultListModel otherListModel = new DefaultListModel();
        for (Pair<String, String> fileNameTitlePair : selectedTaxon.getLinkFiles()) {
            String fileName = fileNameTitlePair.getFirst();
            String fileTitle = fileNameTitlePair.getSecond();

            if (fileTitle != null) {
                otherListModel.addElement(fileTitle);
            } else {
                otherListModel.addElement(fileName);
            }

            _cmds.add(new OpenLinkFileCommand(fileName, fileTitle));
        }

        for (Pair<String, String> subjectDirectiveCommandPair : _definedDirectiveCommands) {
            String subject = subjectDirectiveCommandPair.getFirst();
            String directiveCommand = subjectDirectiveCommandPair.getSecond();

            otherListModel.addElement(subject);
            _cmds.add(new RunDirectiveCommand(directiveCommand, subject));
        }

        // If no link files or directive commands have been defined, display an entry labelled "Full description" that will
        // run the describe command for the taxon
        if (otherListModel.isEmpty()) {
            otherListModel.addElement(fullDescriptionCaption);
            _cmds.add(new RunDirectiveCommand("DESCRIBE (?S) all", fullDescriptionCaption));
        }

        _listOther.setModel(otherListModel);

        // Update illustrations list
        _images = new ArrayList<Image>();
        DefaultListModel illustrationsListModel = new DefaultListModel();
        for (Image img : selectedTaxon.getImages()) {
            _images.add(img);
            illustrationsListModel.addElement(img.getSubjectTextOrFileName());
        }

        if (_images.isEmpty()) {
            illustrationsListModel.addElement(noImagesCaption);
        }

        _listIllustrations.setModel(illustrationsListModel);

        // update button state
        _btnStart.setEnabled(index > 0);
        _btnPrevious.setEnabled(index > 0);
        _btnForward.setEnabled(index < _taxa.size() - 1);
        _btnEnd.setEnabled(index < _taxa.size() - 1);

    }

    @Action
    public void firstTaxon() {
        displayTaxon(0);
    }

    @Action
    public void lastTaxon() {
        displayTaxon(_taxa.size() - 1);
    }

    @Action
    public void nextTaxon() {
        if (_selectedIndex < _taxa.size() - 1) {
            displayTaxon(_selectedIndex + 1);
        }
    }

    @Action
    public void previousTaxon() {
        if (_selectedIndex > 0) {
            displayTaxon(_selectedIndex - 1);
        }
    }

    @Action
    public void displaySelectedTaxonInformation() {
        int[] selectedCommandIndicies = _listOther.getSelectedIndices();
        for (int idx : selectedCommandIndicies) {
            _cmds.get(idx).execute();
        }

        int[] selectedImageIndicies = _listIllustrations.getSelectedIndices();

        int totalNumberOfDialogsToDisplay = selectedCommandIndicies.length + selectedImageIndicies.length;

        if (!_imageDisplayEnabled && selectedImageIndicies.length > 0) {
            _context.getUI().displayErrorMessage(UIUtils.getResourceString("ImageDisplayDisabled.error"));
        } else {
            for (int idx : selectedImageIndicies) {
                displaySelectedTaxonImage(idx, totalNumberOfDialogsToDisplay == 1);
            }
        }

        // Tile the all spawned dialogs once they have finished displaying if
        // there is more than one
        if (totalNumberOfDialogsToDisplay > 1) {
            IntKeyDialogController.tileWindows();
        }
    }

    @Action
    public void displayMultipleImages() {
        List<String> imageSubjects = _context.getImageSubjects();
        MultipleImagesDialog dlg = new MultipleImagesDialog(this, true, getSelectedTaxon(), _taxa, imageSubjects,
                _imageSettings, _context.displayContinuous(), _context.displayScaled(), _context.getUI());
        ((SingleFrameApplication) Application.getInstance()).show(dlg);
    }

    @Action
    public void webSearch() {
        WebSearchDialog websearch = new WebSearchDialog(this);
        websearch.setModal(true);
        Item selectedTaxon = _taxa.get(_selectedIndex);
        ItemFormatter formatter = new ItemFormatter(false, CommentStrippingMode.STRIP_ALL,
                AngleBracketHandlingMode.REMOVE, true, false, true);
        websearch.setSearchTerm(formatter.formatItemDescription(selectedTaxon));
        ((SingleFrameApplication) Application.getInstance()).show(websearch);
    }

    @Action
    public void deselectAllTaxonInformation() {
        _listOther.clearSelection();
        _listIllustrations.clearSelection();
    }

    @Action
    public void done() {
        this.setVisible(false);
    }

    public Item getSelectedTaxon() {
        return _taxa.get(_selectedIndex);
    }

    private void displaySelectedTaxonImage(int imageIndex, boolean fitDialogToFirstImageDisplayed) {
        // Do nothing if the user tries to display the "No Images" caption
        if (_images.isEmpty()) {
            return;
        }

        try {
            Item selectedTaxon = getSelectedTaxon();
            TaxonImageDialog dlg = new TaxonImageDialog(UIUtils.getMainFrame(), _imageSettings, _taxaWithImages,
                    false, !_context.displayContinuous(), _context.displayScaled(), _context.getImageSubjects(),
                    _context.getUI());
            dlg.setAutoSizeAndCenterFirstImageDisplayed(fitDialogToFirstImageDisplayed);
            dlg.displayImagesForTaxon(selectedTaxon, imageIndex);
            ((SingleFrameApplication) Application.getInstance()).show(dlg);
        } catch (IllegalArgumentException ex) {
            // Display error message if unable to display
            _context.getUI()
                    .displayErrorMessage(UIUtils.getResourceString("CouldNotDisplayImage.error", ex.getMessage()));
        }
    }

    /**
     * Display all images for the selected taxon that contain the supplied text.
     * If the supplied text is null or is an empty string, all available images
     * for the selected taxon will be displayed
     * 
     * @param text
     */
    public void displayImagesWithTextInSubject(String text) {
        for (int i = 0; i < _images.size(); i++) {
            Image img = _images.get(i);
            String subjectText = img.getSubjectText();

            if (StringUtils.isEmpty(text) || subjectText.toLowerCase().contains(text.toLowerCase())) {
                displaySelectedTaxonImage(i, false);
            }
        }

        // Tile the all spawned dialogs once they have finished displaying
        // themselves.
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                IntKeyDialogController.tileWindows();
            }
        });
    }

    /**
     * Display any non-image information attached to the current taxon with a
     * subject that contains the supplied text. Link files other than .rtf files
     * are ignored. If the supplied text is null or is an empty string, all
     * available non-image information items (other than .rtf files) for the
     * selected taxon will be displayed
     * 
     * @param text
     */
    public void displayOtherItemsWithTextInDescription(String text) {
        for (InformationDialogCommand cmd : _cmds) {

            // Ignore any link files other than rtf files
            if (cmd instanceof OpenLinkFileCommand) {
                OpenLinkFileCommand openLinkFileCmd = (OpenLinkFileCommand) cmd;
                if (!openLinkFileCmd.getLinkFileName().toLowerCase().endsWith(".rtf")) {
                    continue;
                }
            }

            if (StringUtils.isEmpty(text) || cmd.getDescription().toLowerCase().contains(text.toLowerCase())) {
                cmd.execute();
            }
        }

        // Tile the all spawned dialogs once they have finished displaying
        // themselves.
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                IntKeyDialogController.tileWindows();
            }
        });
    }

    private interface InformationDialogCommand {
        public void execute();

        public String getDescription();
    }

    private class OpenLinkFileCommand implements InformationDialogCommand {

        private String _linkFileName;
        private String _description;

        public OpenLinkFileCommand(String linkFileName, String description) {
            _linkFileName = linkFileName;
            _description = description;
        }

        @Override
        public void execute() {
            URL linkFileURL = _infoSettings.findFileOnResourcePath(_linkFileName, false);

            if (linkFileURL == null) {
                _context.getUI()
                        .displayErrorMessage(UIUtils.getResourceString("CouldNotLocateFile.error", _linkFileName));
            }

            try {
                _context.getUI().displayFile(linkFileURL, _description);
            } catch (Exception ex) {
                _context.getUI().displayErrorMessage(
                        UIUtils.getResourceString("CouldNotLocateFile.error", linkFileURL.toString()));
            }
        }

        @Override
        public String getDescription() {
            return _description;
        }

        public String getLinkFileName() {
            return _linkFileName;
        }
    }

    private class RunDirectiveCommand implements InformationDialogCommand {

        private String _directiveCommand;
        private String _description;

        public RunDirectiveCommand(String directiveCommand, String description) {
            _directiveCommand = directiveCommand;
            _description = description;
        }

        @Override
        public void execute() {
            // substitute ?S for selected taxon number
            Item selectedTaxon = getSelectedTaxon();
            int taxonNumber = selectedTaxon.getItemNumber();

            String command = _directiveCommand.replaceAll("\\?S", Integer.toString(taxonNumber));

            // parse and run directive
            _context.parseAndExecuteDirective(command);
        }

        @Override
        public String getDescription() {
            return _description;
        }
    }
}