org.rdv.ui.ExportVideoDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.rdv.ui.ExportVideoDialog.java

Source

/*
 * RDV
 * Real-time Data Viewer
 * http://rdv.googlecode.com/
 * 
 * Copyright (c) 2005-2007 University at Buffalo
 * Copyright (c) 2005-2007 NEES Cyberinfrastructure Center
 * Copyright (c) 2008 Palta Software
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 * $URL$
 * $Revision$
 * $Date$
 * $Author$
 */

package org.rdv.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
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.MouseListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rdv.DataViewer;
import org.rdv.data.Channel;
import org.rdv.rbnb.EventMarker;
import org.rdv.rbnb.ProgressListener;
import org.rdv.rbnb.RBNBController;
import org.rdv.rbnb.RBNBExport;
import org.rdv.util.ReadableStringComparator;

public class ExportVideoDialog extends JDialog implements ProgressListener {

    /** serialization version identifier */
    private static final long serialVersionUID = -5129293655952117325L;

    static Log log = LogFactory.getLog(ExportVideoDialog.class.getName());

    ExportVideoDialog dialog;

    RBNBController rbnb;
    RBNBExport export;
    boolean exporting;

    JButton startTimeButton;
    JLabel durationLabel;
    JButton endTimeButton;

    TimeSlider timeSlider;

    JList videoChannelList;
    DefaultListModel videoChannelModel;

    JTextField directoryTextField;
    JButton directoryButton;

    JProgressBar exportProgressBar;

    JButton exportButton;
    JButton cancelButton;

    List<String> channels;

    public ExportVideoDialog(JFrame owner, RBNBController rbnb, List<String> channels) {

        super(owner);

        this.dialog = this;

        this.rbnb = rbnb;

        this.channels = channels;
        Collections.sort(channels, new ReadableStringComparator());

        export = new RBNBExport(rbnb.getRBNBHostName(), rbnb.getRBNBPortNumber());
        exporting = false;

        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        setTitle("Export video to disk");
        setChannelModel();
        initComponents();
    }

    private void setChannelModel() {

        videoChannelModel = new DefaultListModel();

        for (int i = 0; i < channels.size(); i++) {
            String channelName = (String) channels.get(i);
            Channel channel = rbnb.getChannel(channelName);
            String mime = channel.getMetadata("mime");

            if (mime.equals("image/jpeg") || mime.equals("video/jpeg")) {
                videoChannelModel.addElement(new ExportChannel(channelName));
            }

        }
    }

    private void initComponents() {

        JPanel container = new JPanel();
        setContentPane(container);

        InputMap inputMap = container.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = container.getActionMap();

        container.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.weighty = 0;
        c.gridwidth = 1;
        c.gridheight = 1;
        c.ipadx = 0;
        c.ipady = 0;

        JLabel headerLabel = new JLabel("Select the time range and video channels to export.");
        headerLabel.setBackground(Color.white);
        headerLabel.setOpaque(true);
        headerLabel.setBorder(
                BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.gray),
                        BorderFactory.createEmptyBorder(10, 10, 10, 10)));
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 0;
        c.gridx = 0;
        c.gridy = 0;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.anchor = GridBagConstraints.NORTHEAST;
        c.insets = new java.awt.Insets(0, 0, 0, 0);
        container.add(headerLabel, c);

        JPanel timeButtonPanel = new JPanel();
        timeButtonPanel.setLayout(new BorderLayout());

        MouseListener hoverMouseListener = new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                e.getComponent().setForeground(Color.red);
            }

            public void mouseExited(MouseEvent e) {
                e.getComponent().setForeground(Color.blue);
            }
        };

        startTimeButton = new JButton();
        startTimeButton.setBorder(null);
        startTimeButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        startTimeButton.setForeground(Color.blue);
        startTimeButton.addMouseListener(hoverMouseListener);
        startTimeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                double startTime = DateTimeDialog.showDialog(ExportVideoDialog.this, timeSlider.getStart(),
                        timeSlider.getMinimum(), timeSlider.getEnd());
                if (startTime >= 0) {
                    timeSlider.setStart(startTime);
                }
            }
        });
        timeButtonPanel.add(startTimeButton, BorderLayout.WEST);

        durationLabel = new JLabel();
        durationLabel.setHorizontalAlignment(JLabel.CENTER);
        timeButtonPanel.add(durationLabel, BorderLayout.CENTER);

        endTimeButton = new JButton();
        endTimeButton.setBorder(null);
        endTimeButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        endTimeButton.setForeground(Color.blue);
        endTimeButton.addMouseListener(hoverMouseListener);
        endTimeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                double endTime = DateTimeDialog.showDialog(ExportVideoDialog.this, timeSlider.getEnd(),
                        timeSlider.getStart(), timeSlider.getMaximum());
                if (endTime >= 0) {
                    timeSlider.setEnd(endTime);
                }
            }
        });
        timeButtonPanel.add(endTimeButton, BorderLayout.EAST);

        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 0;
        c.gridx = 0;
        c.gridy = 1;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.anchor = GridBagConstraints.NORTHEAST;
        c.insets = new java.awt.Insets(10, 10, 10, 10);
        container.add(timeButtonPanel, c);

        timeSlider = new TimeSlider();
        timeSlider.setValueChangeable(false);
        timeSlider.setValueVisible(false);
        timeSlider.addTimeAdjustmentListener(new TimeAdjustmentListener() {
            public void timeChanged(TimeEvent event) {
            }

            public void rangeChanged(TimeEvent event) {
                updateTimeRangeLabel();
            }

            public void boundsChanged(TimeEvent event) {
            }
        });
        updateTimeRangeLabel();
        updateTimeBounds();

        List<EventMarker> markers = rbnb.getMarkerManager().getMarkers();
        for (EventMarker marker : markers) {
            timeSlider.addMarker(marker);
        }

        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 0;
        c.gridx = 0;
        c.gridy = 2;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.anchor = GridBagConstraints.NORTHEAST;
        c.insets = new java.awt.Insets(0, 10, 10, 10);
        container.add(timeSlider, c);

        JLabel numericHeaderLabel = new JLabel("Video Channels:");
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 0;
        c.gridx = 0;
        c.gridy = 3;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.anchor = GridBagConstraints.NORTHEAST;
        c.insets = new java.awt.Insets(0, 10, 10, 10);
        container.add(numericHeaderLabel, c);

        videoChannelList = new JList(videoChannelModel);
        videoChannelList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        videoChannelList.setCellRenderer(new CheckListRenderer());
        videoChannelList.setVisibleRowCount(10);
        videoChannelList.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                int index = videoChannelList.locationToIndex(e.getPoint());
                ExportChannel item = (ExportChannel) videoChannelList.getModel().getElementAt(index);
                item.setSelected(!item.isSelected());
                Rectangle rect = videoChannelList.getCellBounds(index, index);
                videoChannelList.repaint(rect);

                updateTimeBounds();
            }
        });
        JScrollPane scrollPane = new JScrollPane(videoChannelList);
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 0;
        c.weighty = 1;
        c.gridx = 0;
        c.gridy = 4;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.anchor = GridBagConstraints.NORTHEAST;
        c.insets = new java.awt.Insets(0, 10, 10, 10);
        container.add(scrollPane, c);

        c.fill = GridBagConstraints.NONE;
        c.weightx = 0;
        c.weighty = 0;
        c.gridx = 0;
        c.gridy = 5;
        c.gridwidth = 1;
        c.anchor = GridBagConstraints.NORTHWEST;
        c.insets = new java.awt.Insets(0, 10, 10, 5);
        container.add(new JLabel("Choose Directory: "), c);

        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 1;
        c.gridx = 1;
        c.gridy = 5;
        c.gridwidth = 1;
        c.anchor = GridBagConstraints.NORTHWEST;
        directoryTextField = new JTextField(20);
        c.insets = new java.awt.Insets(0, 0, 10, 5);
        container.add(directoryTextField, c);

        directoryTextField.setText(UIUtilities.getCurrentDirectory().getAbsolutePath());
        directoryButton = new JButton("Browse");
        directoryButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                File selectedDirectory = UIUtilities.getDirectory("Select export directory");
                if (selectedDirectory != null) {
                    directoryTextField.setText(selectedDirectory.getAbsolutePath());
                }
            }
        });
        c.fill = GridBagConstraints.NONE;
        c.weightx = 0;
        c.gridx = 2;
        c.gridy = 5;
        c.gridwidth = 1;
        c.anchor = GridBagConstraints.NORTHWEST;
        c.insets = new java.awt.Insets(0, 0, 10, 10);
        container.add(directoryButton, c);

        exportProgressBar = new JProgressBar(0, 100000);
        exportProgressBar.setStringPainted(true);
        exportProgressBar.setValue(0);
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 0.5;
        c.gridx = 0;
        c.gridy = 6;
        c.gridwidth = GridBagConstraints.REMAINDER;
        ;
        c.anchor = GridBagConstraints.CENTER;
        c.insets = new java.awt.Insets(0, 10, 10, 10);
        container.add(exportProgressBar, c);

        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout());

        Action exportAction = new AbstractAction() {
            /** serialization version identifier */
            private static final long serialVersionUID = 1547500154252213911L;

            public void actionPerformed(ActionEvent e) {
                exportVideo();
            }
        };
        exportAction.putValue(Action.NAME, "Export");
        inputMap.put(KeyStroke.getKeyStroke("ENTER"), "export");
        actionMap.put("export", exportAction);
        exportButton = new JButton(exportAction);
        panel.add(exportButton);

        Action cancelAction = new AbstractAction() {
            /** serialization version identifier */
            private static final long serialVersionUID = -7440298547807878651L;

            public void actionPerformed(ActionEvent e) {
                cancel();
            }
        };
        cancelAction.putValue(Action.NAME, "Cancel");
        inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), "cancel");
        actionMap.put("cancel", cancelAction);
        cancelButton = new JButton(cancelAction);
        panel.add(cancelButton);

        c.fill = GridBagConstraints.NONE;
        c.weightx = 0.5;
        c.gridx = 0;
        c.gridy = 7;
        c.gridwidth = GridBagConstraints.REMAINDER;
        ;
        c.anchor = GridBagConstraints.LINE_END;
        c.insets = new java.awt.Insets(0, 0, 10, 5);
        container.add(panel, c);

        pack();
        if (getWidth() < 600) {
            setSize(600, getHeight());
        }

        directoryTextField.requestFocusInWindow();

        setLocationByPlatform(true);
        setVisible(true);
    }

    private void disableUI() {
        startTimeButton.setEnabled(false);
        endTimeButton.setEnabled(false);
        videoChannelList.setEnabled(false);
        directoryTextField.setEnabled(false);
        directoryButton.setEnabled(false);
        exportButton.setEnabled(false);
    }

    private void enableUI() {
        startTimeButton.setEnabled(true);
        endTimeButton.setEnabled(true);
        videoChannelList.setEnabled(true);
        directoryTextField.setEnabled(true);
        directoryButton.setEnabled(true);
        exportButton.setEnabled(true);
    }

    private void updateTimeBounds() {
        List<String> selectedChannels = getSelectedChannels();
        if (selectedChannels.size() == 0) {
            return;
        }

        double minimum = Double.MAX_VALUE;
        double maximum = 0;

        for (String channelName : selectedChannels) {
            Channel channel = rbnb.getChannel(channelName);
            if (channel == null) {
                continue;
            }

            double channelStart = channel.getStart();
            double channelDuration = channel.getDuration();
            double channelEnd = channelStart + channelDuration;

            if (channelStart < minimum) {
                minimum = channelStart;
            }

            if (channelEnd > maximum) {
                maximum = channelEnd;
            }
        }

        timeSlider.setValues(minimum, maximum);
    }

    private void updateTimeRangeLabel() {
        double start = timeSlider.getStart();
        double end = timeSlider.getEnd();
        double duration = end - start;

        startTimeButton.setText(DataViewer.formatDate(start));
        durationLabel.setText(DataViewer.formatSeconds(duration));
        endTimeButton.setText(DataViewer.formatDate(end));
    }

    private List<String> getSelectedChannels() {
        List<String> selectedChannels = new ArrayList<String>();
        for (int i = 0; i < videoChannelModel.size(); i++) {
            ExportChannel channel = (ExportChannel) videoChannelModel.get(i);
            if (channel.isSelected()) {
                selectedChannels.add(channel.toString());
            }
        }

        return selectedChannels;
    }

    private boolean createDirectory(File directory) {
        File file = new File(directory.getPath());
        return file.mkdirs();
    }

    private boolean checkDirectory(File directory) {

        if (directory.exists()) {
            if (directory.isDirectory()) {
                int overwriteReturn = JOptionPane.showConfirmDialog(null,
                        directory.getName() + " already exists.\nResume writing in the same folder?",
                        "Write into existing directory?", JOptionPane.YES_NO_OPTION);
                if (overwriteReturn == JOptionPane.NO_OPTION) {
                    return false;
                }
            } else {
                JOptionPane.showMessageDialog(null,
                        "Could not create directory " + directory.getPath()
                                + "\nA file with that name already exists!",
                        "Create Directory error", JOptionPane.INFORMATION_MESSAGE);
                return false;
            }

        } else {
            int createDir = JOptionPane.showConfirmDialog(null,
                    directory.getPath() + " does NOT exist. Directory will be created", "Create new directory?",
                    JOptionPane.YES_NO_OPTION);
            if (createDir == JOptionPane.YES_OPTION) {
                if (!createDirectory(directory)) {
                    JOptionPane.showMessageDialog(null, "Error: Could not create directory " + directory.getPath(),
                            "Create Directory error", JOptionPane.INFORMATION_MESSAGE);
                    return false;
                }

            } else {
                return false;
            }

        }

        return true;
    }

    private void exportVideo() {

        List<String> selectedChannels = getSelectedChannels();

        if (selectedChannels.size() == 0) {
            JOptionPane.showMessageDialog(this, "No video channels selected!", "Export Video channels",
                    JOptionPane.ERROR_MESSAGE);
            return;
        }

        File directory = new File(directoryTextField.getText());

        if (!checkDirectory(directory)) {
            return;
        }

        disableUI();

        double start = timeSlider.getStart();
        double end = timeSlider.getEnd();

        if (start == end) {
            JOptionPane.showMessageDialog(this, "The start and end export time must not be the same.",
                    "Export Video Error", JOptionPane.ERROR_MESSAGE);
            return;
        }

        exporting = true;
        export.startExport(null, null, selectedChannels, directory,

                start, end, this);
    }

    private void cancel() {
        if (exporting) {
            export.cancelExport();
        } else {
            dispose();
        }
    }

    public void postProgress(double progress) {
        exportProgressBar.setValue((int) (progress * 100000));
    }

    public void postCompletion() {
        exporting = false;
        dispose();
        JOptionPane.showMessageDialog(this, "Export complete.", "Export complete", JOptionPane.INFORMATION_MESSAGE);
    }

    public void postError(String errorMessage) {
        exportProgressBar.setValue(0);
        exporting = false;
        enableUI();
        JOptionPane.showMessageDialog(this, errorMessage, "Error", JOptionPane.ERROR_MESSAGE);
    }

    class ExportChannel {
        String channelName;
        boolean selected;

        public ExportChannel(String channelName) {
            this.channelName = channelName;
            selected = true;
        }

        public boolean isSelected() {
            return selected;
        }

        public void setSelected(boolean selected) {
            this.selected = selected;
        }

        public String toString() {
            return channelName;
        }
    }

    class CheckListRenderer extends JCheckBox implements ListCellRenderer {

        /** serialization version identifier */
        private static final long serialVersionUID = 215713751613298905L;

        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                boolean hasFocus) {
            setEnabled(list.isEnabled());
            setSelected(((ExportChannel) value).isSelected());
            if (index % 2 == 0) {
                setBackground(UIManager.getColor("List.textBackground"));
            } else {
                setBackground(new Color(230, 230, 230));
            }
            setForeground(UIManager.getColor("List.textForeground"));
            setFont(list.getFont());
            setText(value.toString());
            return this;
        }
    }

}