captureplugin.CapturePlugin.java Source code

Java tutorial

Introduction

Here is the source code for captureplugin.CapturePlugin.java

Source

/*
 * CapturePlugin by Andreas Hessel (Vidrec@gmx.de), Bodo Tasche
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * CVS information:
 *  $RCSfile$
 *   $Source$
 *     $Date: 2010-07-14 12:12:05 +0200 (Wed, 14 Jul 2010) $
 *   $Author: ds10 $
 * $Revision: 6679 $
 */
package captureplugin;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

import org.apache.commons.lang.StringUtils;

import util.ui.Localizer;
import util.ui.UiUtilities;
import captureplugin.drivers.DeviceIf;
import devplugin.ActionMenu;
import devplugin.ContextMenuAction;
import devplugin.PluginInfo;
import devplugin.PluginTreeNode;
import devplugin.Program;
import devplugin.ProgramFieldType;
import devplugin.ProgramReceiveTarget;
import devplugin.SettingsTab;
import devplugin.ThemeIcon;
import devplugin.Version;

/**
 * Plugin to send the TV-Data to an external program
 *
 * @author Andreas Hessel, Bodo Tasche
 */
public class CapturePlugin extends devplugin.Plugin {
    private static final Version mVersion = new Version(3, 00);

    /**
     * Translator
     */
    private static final Localizer mLocalizer = Localizer.getLocalizerFor(CapturePlugin.class);

    /**
     * mData that stores the Settings
     */
    private CapturePluginData mConfig = new CapturePluginData();

    /**
     * Current Marked Programs
     */
    private Vector<Program> mMarkedPrograms = new Vector<Program>();

    /**
     * The Singleton
     */
    private static CapturePlugin mInstance = null;

    private boolean mAllowedToShowDialog = false;
    private boolean mNeedsUpdate = false;

    private Properties mSettings;

    /**
     * Root-Node for the Program-Tree
     */
    private PluginTreeNode mRootNode = new PluginTreeNode(this, false);
    private static final String RECORD = "##record";
    private static final String REMOVE = "##remove";

    private PluginInfo mPluginInfo;

    /**
     * Creates the Plugin
     */
    public CapturePlugin() {
        mInstance = this;
    }

    /**
     * Returns this Instance
     *
     * @return Instance
     */
    public static CapturePlugin getInstance() {
        return mInstance;
    }

    /**
     * Called by the host-application during start-up. Implement this method to
     * load any objects from the file system.
     *
     * @see #writeData(ObjectOutputStream)
     */
    public void readData(ObjectInputStream in) throws IOException, ClassNotFoundException {
        mConfig = new CapturePluginData();
        mConfig.readData(in, this);
        updateMarkedPrograms();
    }

    /**
     * Counterpart to loadData. Called when the application shuts down.
     * Implement this method to store any objects to the file system.
     *
     * @see #readData(ObjectInputStream)
     */
    public void writeData(ObjectOutputStream out) throws IOException {
        mConfig.writeData(out);
    }

    /**
     * Called by the host-application during start-up. Implements this method to
     * load your plugins settings from the file system.
     */
    public void loadSettings(Properties settings) {
        if (settings == null) {
            mSettings = new Properties();
        } else {
            mSettings = settings;
        }
    }

    /**
     * Called by the host-application during shut-down. Implements this method
     * to store your plugins settings to the file system.
     */
    public Properties storeSettings() {
        return mSettings;
    }

    public static Version getVersion() {
        return mVersion;
    }

    /**
     * Implement this function to provide information about your plugin.
     */
    public PluginInfo getInfo() {
        if (mPluginInfo == null) {
            String name = mLocalizer.msg("CapturePlugin", "Capture Plugin");
            String desc = mLocalizer.msg("Desc", "Starts a external Program with configurable Parameters");
            String author = "Bodo Tasche, Andreas Hessel";

            mPluginInfo = new PluginInfo(CapturePlugin.class, name, desc, author);
        }
        return mPluginInfo;
    }

    /**
     * Returns a new SettingsTab object, which is added to the settings-window.
     */
    public SettingsTab getSettingsTab() {
        return new CapturePluginSettingsTab((JFrame) getParentFrame(), this);
    }

    public ActionMenu getContextMenuActions(final Program program) {

        final DeviceIf[] devices = mConfig.getDeviceArray();

        final Window parent = UiUtilities.getLastModalChildOf(getParentFrame());

        Action mainaction = new devplugin.ContextMenuAction();
        mainaction.putValue(Action.NAME, mLocalizer.msg("record", "record Program"));
        mainaction.putValue(Action.SMALL_ICON, createImageIcon("mimetypes", "video-x-generic", 16));

        ArrayList<ActionMenu> actionList = new ArrayList<ActionMenu>();

        for (final DeviceIf dev : devices) {
            Action action = new ContextMenuAction();
            action.putValue(Action.NAME, dev.getName());

            ArrayList<AbstractAction> commandList = new ArrayList<AbstractAction>();

            if (dev.isAbleToAddAndRemovePrograms()) {
                final Program test = dev.getProgramForProgramInList(program);

                if (test != null) {
                    AbstractAction caction = new AbstractAction() {
                        public void actionPerformed(ActionEvent evt) {
                            dev.remove(parent, test);
                            updateMarkedPrograms();
                        }
                    };
                    caction.putValue(Action.NAME, Localizer.getLocalization(Localizer.I18N_DELETE));
                    commandList.add(caction);
                } else {
                    AbstractAction caction = new AbstractAction() {
                        public void actionPerformed(ActionEvent evt) {
                            if (dev.add(parent, program)) {
                                dev.sendProgramsToReceiveTargets(new Program[] { program });
                            }
                            updateMarkedPrograms();
                        }
                    };
                    caction.putValue(Action.NAME, mLocalizer.msg("record", "record"));
                    commandList.add(caction);
                }

            }

            String[] commands = dev.getAdditionalCommands();

            if (commands != null) {
                for (int y = 0; y < commands.length; y++) {

                    final int num = y;

                    AbstractAction caction = new AbstractAction() {

                        public void actionPerformed(ActionEvent evt) {
                            dev.executeAdditionalCommand(parent, num, program);
                        }
                    };
                    caction.putValue(Action.NAME, commands[y]);
                    commandList.add(caction);
                }
            }

            if (!commandList.isEmpty()) {
                actionList.add(new ActionMenu(action, commandList.toArray(new Action[commandList.size()])));
            }
        }

        if (actionList.size() == 1) {
            ActionMenu menu = actionList.get(0);

            if (menu.getSubItems().length == 0) {
                return null;
            }

            if (menu.getSubItems().length == 1) {
                Action action = menu.getSubItems()[0].getAction();
                action.putValue(Action.SMALL_ICON, createImageIcon("mimetypes", "video-x-generic", 16));
                return new ActionMenu(action);
            } else {
                mainaction.putValue(Action.NAME, menu.getTitle());
                return new ActionMenu(mainaction, menu.getSubItems());
            }

        }

        ActionMenu[] actions = new ActionMenu[actionList.size()];
        actionList.toArray(actions);

        if (actions.length == 0) {
            return null;
        }

        return new ActionMenu(mainaction, actions);
    }

    /**
     * Updates the marked Programs.
     */
    protected void updateMarkedPrograms() {
        Vector<Program> list = getMarkedByDevices();

        for (Program aList : list) {

            if (mMarkedPrograms.contains(aList)) {
                mMarkedPrograms.remove(aList);
            }

            aList.mark(this);
        }

        for (Program mMarkedProgram : mMarkedPrograms) {
            mMarkedProgram.unmark(this);
        }

        mMarkedPrograms = list;

        updateTreeNode();
        super.saveMe();
    }

    /**
     * This Function Iterates over all Devices and collects the list of Programs
     * to mark...
     *
     * @return List with all Programs to mark
     */
    private Vector<Program> getMarkedByDevices() {
        Vector<Program> v = new Vector<Program>();

        for (Object o : mConfig.getDevices()) {
            DeviceIf device = (DeviceIf) o;

            Program[] programs = device.getProgramList();

            if (programs != null) {
                for (Program program : programs) {
                    if (!v.contains(program)) {
                        v.add(program);
                    }
                }
            }
        }

        return v;
    }

    public ActionMenu getButtonAction() {
        AbstractAction action = new AbstractAction() {

            public void actionPerformed(ActionEvent evt) {
                showDialog();
            }
        };
        action.putValue(Action.NAME, mLocalizer.msg("CapturePlugin", "Capture Plugin"));
        action.putValue(Action.SMALL_ICON, createImageIcon("mimetypes", "video-x-generic", 16));
        action.putValue(BIG_ICON, createImageIcon("mimetypes", "video-x-generic", 22));

        return new ActionMenu(action);
    }

    /**
     * This method is invoked by the host-application if the user has chosen
     * your plugin from the menu.
     */
    protected void showDialog() {
        CapturePluginDialog dialog = new CapturePluginDialog(getParentFrame(), mConfig);

        layoutWindow("captureDlg", dialog, new Dimension(500, 450));

        if (mConfig.getDevices().isEmpty()) {
            dialog.show(CapturePluginPanel.TAB_DEVICELIST);
        } else {
            dialog.show(CapturePluginPanel.TAB_PROGRAMLIST);
        }

        updateMarkedPrograms();
    }

    public ThemeIcon getMarkIconFromTheme() {
        return new ThemeIcon("mimetypes", "video-x-generic", 16);
    }

    /**
     * Sets the CaputePluginData
     *
     * @param data CapturePluginData
     */
    public void setCapturePluginData(CapturePluginData data) {
        mConfig = data;
    }

    /**
     * Returns the CapturePluginData
     *
     * @return The CapaturePluginData
     */
    public CapturePluginData getCapturePluginData() {
        return mConfig;
    }

    /**
     * Update the TreeNode
     */
    private void updateTreeNode() {
        mRootNode.removeAllChildren();
        mRootNode.removeAllActions();

        for (Object o : mConfig.getDevices()) {
            final DeviceIf device = (DeviceIf) o;

            PluginTreeNode node;
            if (mConfig.getDevices().size() > 1) {
                node = new PluginTreeNode(device.getName());
                mRootNode.add(node);
            } else {
                node = mRootNode;
            }

            if (device.isAbleToAddAndRemovePrograms()) {
                node.getMutableTreeNode().setProgramReceiveTarget(new ProgramReceiveTarget(this,
                        device.getName() + " - " + mLocalizer.msg("record", "record"), device.getId() + RECORD));
            }

            Program[] programs = device.getProgramList();

            if (programs != null) {
                for (Program program : programs) {
                    node.addProgram(program);
                }
            }

            node.addAction(new AbstractAction(mLocalizer.msg("configure", "Configure '{0}'", device.getName())) {
                @Override
                public void actionPerformed(ActionEvent e) {
                    device.configDevice(UiUtilities.getBestDialogParent(getParentFrame()));
                    updateTreeNode();
                }
            });
        }

        mRootNode.update();
    }

    /**
     * Get the Root-Node.
     * The CapturePlugin handles all Programs for itself. Some
     * Devices can remove Programs externaly
     */
    public PluginTreeNode getRootNode() {
        return mRootNode;
    }

    public boolean canUseProgramTree() {
        return true;
    }

    @Override
    public boolean canReceiveProgramsWithTarget() {
        return getProgramReceiveTargets().length > 0;
    }

    @Override
    public boolean receivePrograms(Program[] programArr, ProgramReceiveTarget receiveTarget) {
        if (receiveTarget == null || receiveTarget.getTargetId() == null
                || receiveTarget.getTargetId().indexOf('#') == -1) {
            return false;
        }

        String id = receiveTarget.getTargetId();
        String deviceid = StringUtils.substringBefore(id, "#");
        String command = id.substring(id.indexOf('#'));

        for (DeviceIf device : mConfig.getDevices()) {
            if (device.getId().equals(deviceid)) {
                if (command.equals(REMOVE)) {
                    for (Program program : programArr) {
                        if (device.isInList(program)) {
                            device.remove(getParentFrame(), program);
                        }
                    }
                    updateMarkedPrograms();
                    return true;
                } else if (command.equals(RECORD)) {
                    ArrayList<Program> successfullPrograms = new ArrayList<Program>(programArr.length);

                    for (Program program : programArr) {
                        if (device.add(getParentFrame(), program)) {
                            successfullPrograms.add(program);
                        }
                    }
                    device.sendProgramsToReceiveTargets(
                            successfullPrograms.toArray(new Program[successfullPrograms.size()]));
                    updateMarkedPrograms();
                    return true;
                }

                if (command.startsWith("#_")) {
                    command = command.substring(2);

                    String[] cmdstr = device.getAdditionalCommands();

                    for (int i = 0; i < cmdstr.length; i++) {
                        if (cmdstr[i].equals(command)) {
                            for (Program program : programArr) {
                                device.executeAdditionalCommand(getParentFrame(), i, program);
                            }
                            return true;
                        }
                    }

                }
            }
        }

        return false;
    }

    @Override
    public ProgramReceiveTarget[] getProgramReceiveTargets() {
        ArrayList<ProgramReceiveTarget> targets = new ArrayList<ProgramReceiveTarget>();

        for (DeviceIf device : mConfig.getDevices()) {
            if (device.isAbleToAddAndRemovePrograms()) {
                targets.add(new ProgramReceiveTarget(this,
                        device.getName() + " - " + mLocalizer.msg("record", "record"), device.getId() + RECORD));
                targets.add(new ProgramReceiveTarget(this,
                        device.getName() + " - " + mLocalizer.msg("remove", "remove"), device.getId() + REMOVE));
            }

            for (String command : device.getAdditionalCommands()) {
                targets.add(new ProgramReceiveTarget(this, device.getName() + " - " + command,
                        device.getId() + "#_" + command));
            }
        }

        return targets.toArray(new ProgramReceiveTarget[targets.size()]);
    }

    public void handleTvBrowserStartFinished() {
        mAllowedToShowDialog = true;

        if (mNeedsUpdate) {
            handleTvDataUpdateFinished();
        }
    }

    /**
     * Check the programs after data update.
     */
    public void handleTvDataUpdateFinished() {
        mNeedsUpdate = true;

        if (mAllowedToShowDialog) {
            mNeedsUpdate = false;

            DeviceIf[] devices = mConfig.getDeviceArray();

            final DefaultTableModel model = new DefaultTableModel() {
                public boolean isCellEditable(int row, int column) {
                    return false;
                }
            };

            model.setColumnCount(5);
            model.setColumnIdentifiers(new String[] { mLocalizer.msg("device", "Device"),
                    Localizer.getLocalization(Localizer.I18N_CHANNEL), mLocalizer.msg("date", "Date"),
                    ProgramFieldType.START_TIME_TYPE.getLocalizedName(),
                    ProgramFieldType.TITLE_TYPE.getLocalizedName() });

            JTable table = new JTable(model);
            table.getTableHeader().setReorderingAllowed(false);
            table.getTableHeader().setResizingAllowed(false);
            table.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
                public Component getTableCellRendererComponent(JTable renderTable, Object value, boolean isSelected,
                        boolean hasFocus, int row, int column) {
                    Component c = super.getTableCellRendererComponent(renderTable, value, isSelected, hasFocus, row,
                            column);

                    if (value instanceof DeviceIf) {
                        if (((DeviceIf) value).getDeleteRemovedProgramsAutomatically() && !isSelected) {
                            c.setForeground(Color.red);
                        }
                    }

                    return c;
                }
            });

            int[] columnWidth = new int[5];

            for (int i = 0; i < columnWidth.length; i++) {
                columnWidth[i] = UiUtilities.getStringWidth(table.getFont(), model.getColumnName(i)) + 10;
            }

            for (DeviceIf device : devices) {
                Program[] deleted = device.checkProgramsAfterDataUpdateAndGetDeleted();

                if (deleted != null && deleted.length > 0) {
                    for (Program p : deleted) {
                        if (device.getDeleteRemovedProgramsAutomatically() && !p.isExpired() && !p.isOnAir()) {
                            device.remove(UiUtilities.getLastModalChildOf(getParentFrame()), p);
                        } else {
                            device.removeProgramWithoutExecution(p);
                        }

                        if (!p.isExpired()) {
                            Object[] o = new Object[] { device, p.getChannel().getName(), p.getDateString(),
                                    p.getTimeString(), p.getTitle() };

                            for (int i = 0; i < columnWidth.length; i++) {
                                columnWidth[i] = Math.max(columnWidth[i],
                                        UiUtilities.getStringWidth(table.getFont(), o[i].toString()) + 10);
                            }

                            model.addRow(o);
                        }
                    }
                }

                device.getProgramList();
            }

            if (model.getRowCount() > 0) {
                int sum = 0;

                for (int i = 0; i < columnWidth.length; i++) {
                    table.getColumnModel().getColumn(i).setPreferredWidth(columnWidth[i]);

                    if (i < columnWidth.length - 1) {
                        table.getColumnModel().getColumn(i).setMaxWidth(columnWidth[i]);
                    }

                    sum += columnWidth[i];
                }

                JScrollPane scrollPane = new JScrollPane(table);
                scrollPane.setPreferredSize(new Dimension(450, 250));

                if (sum > 500) {
                    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
                    scrollPane.getViewport().setPreferredSize(
                            new Dimension(sum, scrollPane.getViewport().getPreferredSize().height));
                }

                JButton export = new JButton(mLocalizer.msg("exportList", "Export list"));
                export.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        JFileChooser chooser = new JFileChooser();
                        chooser.setDialogType(JFileChooser.SAVE_DIALOG);
                        chooser.setFileFilter(new FileFilter() {
                            public boolean accept(File f) {
                                return f.isDirectory() || f.toString().toLowerCase().endsWith(".txt");
                            }

                            public String getDescription() {
                                return "*.txt";
                            }
                        });

                        chooser.setSelectedFile(new File("RemovedPrograms.txt"));
                        if (chooser.showSaveDialog(
                                UiUtilities.getLastModalChildOf(getParentFrame())) == JFileChooser.APPROVE_OPTION) {
                            if (chooser.getSelectedFile() != null) {
                                String file = chooser.getSelectedFile().getAbsolutePath();

                                if (!file.toLowerCase().endsWith(".txt") && file.indexOf('.') == -1) {
                                    file = file + ".txt";
                                }

                                if (file.indexOf('.') != -1) {
                                    try {
                                        RandomAccessFile write = new RandomAccessFile(file, "rw");
                                        write.setLength(0);

                                        String eolStyle = File.separator.equals("/") ? "\n" : "\r\n";

                                        for (int i = 0; i < model.getRowCount(); i++) {
                                            StringBuilder line = new StringBuilder();

                                            for (int j = 0; j < model.getColumnCount(); j++) {
                                                line.append(model.getValueAt(i, j)).append(' ');
                                            }

                                            line.append(eolStyle);

                                            write.writeBytes(line.toString());
                                        }

                                        write.close();
                                    } catch (Exception ee) {
                                    }
                                }
                            }
                        }
                    }
                });

                Object[] message = {
                        mLocalizer.msg("deletedText",
                                "The data was changed and the following programs were deleted:"),
                        scrollPane, export };

                JOptionPane pane = new JOptionPane();
                pane.setMessage(message);
                pane.setMessageType(JOptionPane.PLAIN_MESSAGE);

                final JDialog d = pane.createDialog(UiUtilities.getLastModalChildOf(getParentFrame()),
                        mLocalizer.msg("CapturePlugin", "CapturePlugin") + " - "
                                + mLocalizer.msg("deletedTitle", "Deleted programs"));
                d.setResizable(true);
                d.setModal(false);

                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        d.setVisible(true);
                    }
                });
            }
        }
    }

    /**
     * @return The parent frame.
     */
    public Frame getSuperFrame() {
        return getParentFrame();
    }

    public int getMarkPriorityForProgram(Program p) {
        return mConfig.getMarkPriority();
    }
}