org.jimcat.gui.perspective.detail.DetailSideBar.java Source code

Java tutorial

Introduction

Here is the source code for org.jimcat.gui.perspective.detail.DetailSideBar.java

Source

/*
 *  This file is part of JimCat.
 *
 *  JimCat 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 version 2.
 *
 *  JimCat 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 JimCat; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package org.jimcat.gui.perspective.detail;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.HashSet;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import org.apache.commons.io.FileUtils;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.JXTaskPane;
import org.jdesktop.swingx.JXTaskPaneContainer;
import org.jimcat.gui.SwingClient;
import org.jimcat.gui.imageviewer.ImageViewer;
import org.jimcat.gui.rating.RatingEditor;
import org.jimcat.gui.tagtree.TagPanelPopupHandler;
import org.jimcat.gui.tagtree.TagTree;
import org.jimcat.gui.tagtree.TagTreeListener;
import org.jimcat.model.Image;
import org.jimcat.model.ImageMetadata;
import org.jimcat.model.Thumbnail;
import org.jimcat.model.notification.BeanChangeEvent;
import org.jimcat.model.notification.BeanListener;
import org.jimcat.model.tag.Tag;
import org.jvnet.substance.SubstanceLookAndFeel;

/**
 * Represents the SideBar of the Detail Perspective.
 * 
 * $Id: DetailSideBar.java 935 2007-06-15 09:21:09Z 07g1t1u2 $
 * 
 * @author Herbert
 */
public class DetailSideBar extends JPanel implements BeanListener<Image>, ListSelectionListener, TagTreeListener {

    /**
     * dimension of the preview image
     */
    private static final Dimension PREVIEW_DIMENSION = new Dimension(Thumbnail.MAX_THUMBNAIL_SIZE,
            Thumbnail.MAX_THUMBNAIL_SIZE);

    /**
     * the Font used for descriptions
     */
    private static Font labelFont = new Font("Tahoma", Font.BOLD, 11);

    /**
     * image to be displayed
     */
    private ImageViewer image;

    /**
     * the label containing titel
     */
    private JLabel title;

    /**
     * used to display rating
     */
    private RatingEditor rating;

    /**
     * used to display image dimension
     */
    private JLabel dimension;

    /**
     * used to display size
     */
    private JLabel size;

    /**
     * used to display path
     */
    private JLabel path;

    /**
     * the tagtree to modify image tags
     */
    private TagTree tagTree;

    /**
     * the component showing associated tags
     */
    private DetailTagList detailTagList;

    /**
     * the component showing exif infos
     */
    private ExifList exifList;

    /**
     * the image currently displayed
     */
    private Image currentImage;

    /**
     * the table next to this detail panel
     */
    private JXTable table;

    /**
     * the index of the last selected element within the table
     */
    private int lastSelected = 0;

    /**
     * is the selection up to date
     */
    private boolean dirty = true;

    /**
     * only constructor
     * @param table 
     */
    public DetailSideBar(JXTable table) {
        this.table = table;
        initComponents();

        // register as a listener
        table.getModel().addTableModelListener(new ModelListener());
        table.getSelectionModel().addListSelectionListener(this);
    }

    /**
     * build up Component hierarchy
     */
    private void initComponents() {

        title = new JLabel();

        // general settings
        setLayout(new BorderLayout());
        setBorder(new EmptyBorder(0, 15, 0, 15));

        // add preview
        add(createPreviewPanel(), BorderLayout.NORTH);

        // add details
        add(createImageDetail(), BorderLayout.CENTER);

        // load first image
        updateImage();
    }

    /**
     * creates the preview head
     * 
     * @return the JPanel for preview purposes
     */
    private JPanel createPreviewPanel() {
        // preview panel
        JPanel preview = new JPanel();
        BorderLayout previewLayout = new BorderLayout();
        previewLayout.setHgap(5);
        previewLayout.setVgap(5);
        preview.setLayout(new BorderLayout());
        preview.setOpaque(true);

        image = new ImageViewer();
        image.setMinimumSize(PREVIEW_DIMENSION);
        image.setPreferredSize(PREVIEW_DIMENSION);
        image.setMaximumSize(PREVIEW_DIMENSION);
        image.setBorder(new EmptyBorder(5, 5, 5, 5));
        image.setOpaque(false);
        image.addMouseListener(new PreviewImageDoubleClickListener());
        preview.add(image, BorderLayout.CENTER);

        return preview;
    }

    /**
     * creates image Detail - Section
     * 
     * @return the Component used to show details
     */
    private JComponent createImageDetail() {
        JLabel tmp = null;

        // Task Panel
        JXTaskPaneContainer container = new JXTaskPaneContainer();
        container.setOpaque(false);

        // General Infos
        JXTaskPane general = new JXTaskPane();
        general.setOpaque(true);
        general.setTitle("General Info");
        general.setExpanded(true);

        // General info list
        JPanel info = new JPanel();
        GridLayout infoLayout = new GridLayout(0, 2);
        infoLayout.setHgap(5);
        info.setLayout(infoLayout);
        info.setOpaque(false);

        tmp = new JLabel("Title");
        tmp.setFont(labelFont);
        info.add(tmp);
        info.add(title);

        tmp = new JLabel("Rating");
        tmp.setFont(labelFont);
        info.add(tmp);
        rating = new RatingEditor();
        info.add(rating);

        tmp = new JLabel("Dimension");
        tmp.setFont(labelFont);
        info.add(tmp);
        dimension = new JLabel("");
        info.add(dimension);

        tmp = new JLabel("Size");
        tmp.setFont(labelFont);
        info.add(tmp);
        size = new JLabel("");
        info.add(size);

        tmp = new JLabel("Location");
        tmp.setFont(labelFont);
        info.add(tmp);
        path = new JLabel("");
        path.setToolTipText("");
        info.add(path);

        general.add(info);
        container.add(general);

        // Exif data
        JXTaskPane exifs = new JXTaskPane();
        exifs.setOpaque(true);
        exifs.setTitle("Exif Infos");
        exifs.setExpanded(true);
        exifList = new ExifList();
        exifs.add(exifList);
        container.add(exifs);

        // Tags
        JXTaskPane tags = new JXTaskPane();
        tags.setOpaque(true);
        tags.setTitle("Associated Tags");
        tags.setExpanded(true);

        // associated tags-list
        detailTagList = new DetailTagList();
        tags.add(detailTagList);
        container.add(tags);

        // Modify Tags
        JXTaskPane filter = new JXTaskPane();
        filter.setTitle("Modify Tags");
        filter.setExpanded(false);
        filter.setOpaque(true);

        tagTree = new TagTree();
        tagTree.addTagTreeListener(this);

        filter.setLayout(new BorderLayout());
        filter.addMouseListener(new TagPanelPopupHandler(filter));
        filter.add(tagTree, BorderLayout.CENTER);
        container.add(filter);

        JScrollPane pane = new JScrollPane();
        pane.setOpaque(true);
        pane.setBorder(null);
        pane.setViewportView(container);
        pane.putClientProperty(SubstanceLookAndFeel.WATERMARK_TO_BLEED, Boolean.TRUE);
        return pane;
    }

    /**
     * handels Images property changes
     * 
     * @see org.jimcat.model.notification.BeanListener#beanPropertyChanged(org.jimcat.model.notification.BeanChangeEvent)
     */
    @SuppressWarnings("unused")
    public void beanPropertyChanged(BeanChangeEvent<Image> event) {
        // get Image
        Image img = event.getSource();

        // update depending on Property
        switch (event.getProperty()) {
        case IMAGE_TITEL: {
            title.setText(img.getTitle());
            break;
        }
        case IMAGE_METADATA: {
            updateMetadata(img.getMetadata());
            break;
        }
        case IMAGE_EXIF_META: {
            exifList.setExifData(img.getExifMetadata());
            break;
        }
        case IMAGE_TAGS: {
            tagTree.selectTags(img.getTags());
            break;
        }
        // case thumbnail is handeld by component ImageViewer
        // case rating is handeld by component RatingEditor on its own
        default:
            break;
        }
    }

    /**
     * reacts on table-selection changes
     * 
     * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
     */
    public void valueChanged(ListSelectionEvent e) {
        if (!e.getValueIsAdjusting()) {
            // change current image
            ListSelectionModel model = (ListSelectionModel) e.getSource();
            lastSelected = Math.max(model.getMinSelectionIndex(), 0);
            dirty = true;
            updateImage();
        }
    }

    /**
     * exchanges the Image with the last selected image
     */
    private void updateImage() {
        if (dirty) {
            // get Image for index
            DetailTableModel dataModel = (DetailTableModel) table.getModel();
            // update
            setCurrentImage(dataModel.getImageAtRow(lastSelected));
            // reset dirty
            dirty = false;
        }
    }

    /**
     * replaces the current image
     * 
     * @param img
     */
    private void setCurrentImage(Image img) {
        // only if there is a change
        if (img == currentImage) {
            return;
        }

        // unregister
        if (currentImage != null) {
            currentImage.removeListener(this);
        }

        // remove data if img == null
        if (img == null) {
            currentImage = null;
            title.setText("");
            image.setImage(null);
            rating.setImage(null);
            dimension.setText("");
            size.setText("");
            path.setText("");
            path.setToolTipText("");
            exifList.setExifData(null);
            detailTagList.setImage(null);
            tagTree.selectTags(new HashSet<Tag>());
            return;
        }

        // exchange
        currentImage = img;
        // register
        currentImage.addListener(this);

        // update
        title.setText(img.getTitle());
        image.setImage(img);

        // inform rating editor
        rating.setImage(img);

        // update metadata
        updateMetadata(img.getMetadata());

        // update exif infos
        exifList.setExifData(img.getExifMetadata());

        // update taglists
        detailTagList.setImage(img);
        tagTree.selectTags(img.getTags());

    }

    /**
     * update shown metadata
     * 
     * @param metadata
     */
    private void updateMetadata(ImageMetadata metadata) {
        if (metadata != null) {
            // Dimension
            dimension.setText(metadata.getWidth() + "x" + metadata.getHeight());
            // image size
            size.setText(FileUtils.byteCountToDisplaySize(metadata.getSize()));
            // location
            File location = metadata.getPath();
            String strLocation = "";
            if (location != null) {
                strLocation = location.getParent();
            }
            path.setText(formatPath(location));
            path.setToolTipText(strLocation);
        } else {
            dimension.setText("");
            size.setText("");
            path.setText("");
            path.setToolTipText("");
        }
    }

    /**
     * this methode will format the path of an image to be displayed
     * 
     * @param file
     * @return the path formated as String in a readable representation.
     */
    private String formatPath(File file) {
        // check for null
        if (file == null) {
            return "";
        }

        // just return the name of the parent folder
        String dir = file.getParentFile().getName();

        // if it is still to long, cut it of
        if (dir.length() > 15) {
            dir = dir.substring(0, 12) + "...";
        }

        // remove filename
        return dir;
    }

    /**
     * to fix width
     * 
     * @see javax.swing.JComponent#getPreferredSize()
     */
    @Override
    public Dimension getPreferredSize() {
        Dimension dim = super.getPreferredSize();
        // the Thumbnail dimension + some space
        dim.width = Thumbnail.MAX_THUMBNAIL_SIZE + 20;
        return dim;
    }

    // //////////////////////
    // TAG TREE INTERFACE
    // //////////////////////

    /**
     * Add a new Tag to an image
     * 
     * @see org.jimcat.gui.tagtree.TagTreeListener#tagSelected(org.jimcat.model.tag.Tag)
     */
    public void tagSelected(Tag tag) {
        if (currentImage != null) {
            currentImage.addTag(tag);
        }
    }

    /**
     * Remove a Tag from an image
     * 
     * @see org.jimcat.gui.tagtree.TagTreeListener#tagUnSelected(org.jimcat.model.tag.Tag)
     */
    public void tagUnSelected(Tag tag) {
        if (currentImage != null) {
            currentImage.removeTag(tag);
        }
    }

    /**
     * 
     * The PreviewImageDobleClickListener is used to open the fullscreen on
     * double click on the observed component.
     * 
     * 
     * $Id: DetailSideBar.java 935 2007-06-15 09:21:09Z 07g1t1u2 $
     * 
     * @author Michael
     */
    private class PreviewImageDoubleClickListener extends MouseAdapter {

        /**
         * Open fullscreen on left double click event
         * 
         * @see java.awt.event.MouseAdapter#mouseClicked(java.awt.event.MouseEvent)
         */
        @Override
        public void mouseClicked(MouseEvent e) {
            // if it was a left double click open fullscreen perspective
            if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
                SwingClient.getInstance().showFullScreen();
            }
        }

    }

    /**
     * used to be informed about table changes
     */
    private class ModelListener implements TableModelListener {
        /**
         * @see javax.swing.event.TableModelListener#tableChanged(javax.swing.event.TableModelEvent)
         */
        @SuppressWarnings("unused")
        public void tableChanged(TableModelEvent e) {
            ListSelectionModel model = table.getSelectionModel();
            lastSelected = Math.max(model.getMinSelectionIndex(), 0);
            dirty = true;
            updateImage();
        }
    }

}