tvbrowser.extras.favoritesplugin.dlgs.FavoriteTreeModel.java Source code

Java tutorial

Introduction

Here is the source code for tvbrowser.extras.favoritesplugin.dlgs.FavoriteTreeModel.java

Source

/*
 * TV-Browser
 * Copyright (C) 04-2003 Martin Oberhauser (martin@tvbrowser.org)
 *
 * 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:
 *     $Date: 2010-11-15 08:59:46 +0100 (Mon, 15 Nov 2010) $
 *   $Author: bananeweizen $
 * $Revision: 6828 $
 */
package tvbrowser.extras.favoritesplugin.dlgs;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.apache.commons.lang.StringUtils;

import tvbrowser.extras.common.ReminderConfiguration;
import tvbrowser.extras.favoritesplugin.FavoritesPlugin;
import tvbrowser.extras.favoritesplugin.FavoritesPluginProxy;
import tvbrowser.extras.favoritesplugin.core.Favorite;
import tvbrowser.extras.reminderplugin.ReminderPlugin;
import tvbrowser.ui.mainframe.MainFrame;
import util.ui.Localizer;
import util.ui.TVBrowserIcons;
import util.ui.UiUtilities;
import devplugin.Channel;
import devplugin.ContextMenuIf;
import devplugin.Date;
import devplugin.NodeFormatter;
import devplugin.PluginTreeNode;
import devplugin.Program;
import devplugin.ProgramFieldType;
import devplugin.ProgramItem;
import devplugin.ProgramReceiveTarget;

/**
 * The model for the favorite tree.
 *
 * @author Ren Mach
 * @since 2.6
 */
public class FavoriteTreeModel extends DefaultTreeModel {
    private static final Localizer mLocalizer = Localizer.getLocalizerFor(FavoriteTreeModel.class);

    private static FavoriteTreeModel mInstance;

    /**
     * holds all programs which are contained in multiple favorites<br>
     * initialized lazyly
     */
    private ArrayList<Program> mMultiples = null;

    /**
     * Creates an instance of this class.
     *
     * @param root The root node for this model.
     */
    private FavoriteTreeModel(TreeNode root) {
        super(root, true);
    }

    public static FavoriteTreeModel initInstance(Favorite[] favoriteArr) {
        FavoriteNode rootNode = new FavoriteNode("");
        fixRootNode(rootNode);
        for (Favorite fav : favoriteArr) {
            rootNode.add(fav);
        }

        mInstance = new FavoriteTreeModel(rootNode);
        return mInstance;
    }

    public static FavoriteTreeModel initInstance(ObjectInputStream in, int version)
            throws IOException, ClassNotFoundException {
        FavoriteNode rootNode = new FavoriteNode(in, version);
        fixRootNode(rootNode);
        mInstance = new FavoriteTreeModel(rootNode);
        return mInstance;
    }

    /**
     * change the label of the root node after it has been red from disk
     * @param rootNode
     */
    private static void fixRootNode(final FavoriteNode rootNode) {
        String rootLabel = mLocalizer.msg("rootLabel", "All favorites");
        if (StringUtils.isEmpty(rootLabel)) {
            rootLabel = "FAVORITES_ROOT";
        }
        rootNode.setUserObject(rootLabel);
    }

    public static FavoriteTreeModel getInstance() {
        if (mInstance == null) {
            mInstance = initInstance(new Favorite[0]);
        }

        return mInstance;
    }

    public void reload(TreeNode node) {
        super.reload(node);
        @SuppressWarnings("unchecked")
        Enumeration<FavoriteNode> e = node.children();

        while (e.hasMoreElements()) {
            FavoriteNode child = e.nextElement();

            if (child.isDirectoryNode()) {
                reload(child);
            }
        }
    }

    public void reload(FavoriteTree tree, TreeNode node) {
        super.reload(node);
        @SuppressWarnings("unchecked")
        Enumeration<FavoriteNode> e = node.children();

        while (e.hasMoreElements()) {
            FavoriteNode child = e.nextElement();

            if (child.isDirectoryNode()) {
                reload(tree, child);
            }
        }

        FavoriteNode parent = (FavoriteNode) node;

        if (parent.wasExpanded()) {
            tree.expandPath(new TreePath((tree.getModel()).getPathToRoot(node)));
        } else {
            tree.collapsePath(new TreePath((tree.getModel()).getPathToRoot(node)));
        }
    }

    public void reload() {
        reload(root);
    }

    public boolean isLeaf(Object nodeObject) {
        if (nodeObject instanceof FavoriteNode) {
            FavoriteNode node = (FavoriteNode) nodeObject;
            return node.getChildCount() == 0;
        }
        return super.isLeaf(nodeObject);
    }

    /**
     * Gets all favorites in an array.
     *
     * @return All favorites in an array.
     */
    public Favorite[] getFavoriteArr() {
        ArrayList<Favorite> favoriteList = new ArrayList<Favorite>();

        fillFavoriteList((FavoriteNode) getRoot(), favoriteList);

        return favoriteList.toArray(new Favorite[favoriteList.size()]);
    }

    private void fillFavoriteList(FavoriteNode node, ArrayList<Favorite> favoriteList) {
        if (node.isDirectoryNode()) {
            @SuppressWarnings("unchecked")
            Enumeration<FavoriteNode> e = node.children();

            while (e.hasMoreElements()) {
                FavoriteNode child = e.nextElement();

                if (child.isDirectoryNode()) {
                    fillFavoriteList(child, favoriteList);
                } else if (child.containsFavorite()) {
                    favoriteList.add(child.getFavorite());
                }
            }
        }
    }

    /**
     * Deletes a favorite.
     *
     * @param favorite The favorite to delete.
     */
    public void deleteFavorite(Favorite favorite) {
        Program[] delFavPrograms = favorite.getPrograms();
        for (Program program : delFavPrograms) {
            program.unmark(FavoritesPluginProxy.getInstance());
        }

        deleteFavorite((FavoriteNode) getRoot(), favorite);

        String[] reminderServices = favorite.getReminderConfiguration().getReminderServices();

        for (String reminderService : reminderServices) {
            if (ReminderConfiguration.REMINDER_DEFAULT.equals(reminderService)) {
                ReminderPlugin.getInstance().removePrograms(favorite.getPrograms());
            }
        }

        FavoritesPlugin.getInstance().updateRootNode(true);
    }

    /**
     * Check if a program is marked by other Favorites to.
     *
     * @param favorite The Favorite that wants to check this.
     * @param p The program to check.
     * @return True if the program was found in other Favorites than the given one.
     */
    public boolean isContainedByOtherFavorites(Favorite favorite, Program p) {
        return isContainedByOtherFavorites((FavoriteNode) getRoot(), favorite, p);
    }

    private boolean isContainedByOtherFavorites(FavoriteNode node, Favorite favorite, Program p) {
        boolean value = false;

        if (node.isDirectoryNode()) {
            @SuppressWarnings("unchecked")
            Enumeration<FavoriteNode> e = node.children();

            while (e.hasMoreElements()) {
                FavoriteNode child = e.nextElement();

                if (child.isDirectoryNode()) {
                    value = value || isContainedByOtherFavorites(child, favorite, p);
                } else if (child.containsFavorite()) {
                    if (!child.equals(favorite)) {
                        value = value || child.getFavorite().contains(p);
                    }
                }
            }
        }

        return value;
    }

    private void deleteFavorite(FavoriteNode node, Favorite fav) {
        if (node.isDirectoryNode()) {
            @SuppressWarnings("unchecked")
            Enumeration<FavoriteNode> e = node.children();

            while (e.hasMoreElements()) {
                FavoriteNode child = e.nextElement();

                if (child.isDirectoryNode()) {
                    deleteFavorite(child, fav);
                } else if (child.containsFavorite()) {
                    if (child.equals(fav)) {
                        node.remove(child);
                    } else {
                        child.getFavorite().handleContainingPrograms(fav.getPrograms());
                    }
                }
            }
        }

    }

    /**
     * Adds a favorite to this tree at the root node.
     *
     * @param fav The favorite to add.
     */
    public void addFavorite(Favorite fav) {
        addFavorite(fav, (FavoriteNode) getRoot());
    }

    /**
     * Adds a favorite to this tree at the given target node.
     *
     * @param fav
     *          The favorite to add.
     * @param parent
     *          The parent node to add the favorite to or <code>null</code> if the
     *          root node should be used.
     * @return the newly created node for the favorite
     */
    public FavoriteNode addFavorite(Favorite fav, FavoriteNode parent) {
        if (parent == null) {
            parent = (FavoriteNode) getRoot();
        }
        FavoriteNode newNode = parent.add(fav);
        reload(parent);
        FavoritesPlugin.getInstance().updateRootNode(true);
        return newNode;
    }

    public static String getFavoriteLabel(Favorite favorite, Program program) {
        return getFavoriteLabel(favorite, program, null);
    }

    public static String getFavoriteLabel(Favorite favorite, Program p, Channel currentChannel) {
        Date d = p.getDate();
        String progdate;

        Date currentDate = Date.getCurrentDate();

        if (d.equals(currentDate.addDays(-1))) {
            progdate = Localizer.getLocalization(Localizer.I18N_YESTERDAY);
        } else if (d.equals(currentDate)) {
            progdate = Localizer.getLocalization(Localizer.I18N_TODAY);
        } else if (d.equals(currentDate.addDays(1))) {
            progdate = Localizer.getLocalization(Localizer.I18N_TOMORROW);
        } else {
            progdate = p.getDateString();
        }

        String description = progdate + "  " + p.getTimeString();
        if (favorite.getName().compareTo(p.getTitle()) != 0) {
            description = description + "  " + p.getTitle();
        }
        String episode = p.getTextField(ProgramFieldType.EPISODE_TYPE);
        if (StringUtils.isNotBlank(episode)) {
            if (episode.length() <= 3) {
                episode = ProgramFieldType.EPISODE_TYPE.getLocalizedName() + " " + episode;
            }
            description = description + ": " + episode;
        }
        if (null == currentChannel || currentChannel != p.getChannel()) {
            description = description + "  (" + p.getChannel() + ")";
        }
        return description;
    }

    /**
     * Saves the data of this tree into the given stream.
     *
     * @param out The stream to write the data to.
     * @throws IOException Thrown if something went wrong
     */
    public void storeData(ObjectOutputStream out) throws IOException {
        ((FavoriteNode) getRoot()).store(out);
    }

    public void updatePluginTree(final PluginTreeNode node, final ArrayList<Program> allPrograms,
            FavoriteNode parentFavorite) {
        if (parentFavorite == null) {
            parentFavorite = (FavoriteNode) getRoot();
        }

        if (parentFavorite.isDirectoryNode()) {
            @SuppressWarnings("unchecked")
            Enumeration<FavoriteNode> e = parentFavorite.children();

            while (e.hasMoreElements()) {
                final FavoriteNode child = e.nextElement();

                if (child.isDirectoryNode()) {
                    PluginTreeNode newNode = new PluginTreeNode(child.toString());
                    newNode.setGroupingByWeekEnabled(true);

                    updatePluginTree(newNode, allPrograms, child);
                    if (!newNode.isEmpty()) {
                        node.add(newNode);
                    }
                } else {
                    Program[] progArr = child.getFavorite().getWhiteListPrograms();
                    if (progArr.length > 0) {
                        PluginTreeNode newNode = new PluginTreeNode(child.toString());
                        newNode.setGroupingByWeekEnabled(true);
                        newNode.getMutableTreeNode().setIcon(FavoritesPlugin.getFavoritesIcon(16));
                        node.add(newNode);
                        Action editFavorite = new AbstractAction() {
                            public void actionPerformed(ActionEvent e) {
                                FavoritesPlugin.getInstance().editFavorite(child.getFavorite());
                            }
                        };
                        editFavorite.putValue(Action.NAME, mLocalizer.ellipsisMsg("editTree", "Edit"));
                        editFavorite.putValue(Action.SMALL_ICON, TVBrowserIcons.edit(TVBrowserIcons.SIZE_SMALL));

                        Action deleteFavorite = new AbstractAction() {
                            public void actionPerformed(ActionEvent e) {
                                FavoritesPlugin.getInstance().askAndDeleteFavorite(child.getFavorite());
                            }
                        };
                        deleteFavorite.putValue(Action.NAME, mLocalizer.ellipsisMsg("deleteTree", "Delete"));
                        deleteFavorite.putValue(Action.SMALL_ICON,
                                TVBrowserIcons.delete(TVBrowserIcons.SIZE_SMALL));
                        deleteFavorite.putValue(ContextMenuIf.ACTIONKEY_KEYBOARD_EVENT, KeyEvent.VK_DELETE);

                        newNode.addAction(editFavorite);
                        newNode.addAction(deleteFavorite);

                        if (progArr.length <= 10) {
                            newNode.setGroupingByDateEnabled(false);
                        }
                        boolean episodeOnly = progArr.length > 1;
                        for (Program program : progArr) {
                            String episode = program.getTextField(ProgramFieldType.EPISODE_TYPE);
                            if (StringUtils.isBlank(episode)) {
                                episodeOnly = false;
                                break;
                            }
                        }

                        for (Program program : progArr) {
                            PluginTreeNode pNode = newNode.addProgramWithoutCheck(program);
                            allPrograms.add(program);
                            if (episodeOnly || progArr.length <= 10) {
                                pNode.setNodeFormatter(new NodeFormatter() {
                                    public String format(ProgramItem pitem) {
                                        Program p = pitem.getProgram();
                                        return FavoriteTreeModel.getFavoriteLabel(child.getFavorite(), p);
                                    }
                                });
                            }
                        }
                    }
                }
            }
        }
    }

    /** Calculates the number of programs contained in the children
    *
    * @param node
    *          use this Node
    * @return Number of Child-Nodes
    */
    public static int[] getProgramsCount(FavoriteNode node) {
        int[] count = new int[2];

        Date currentDate = Date.getCurrentDate();
        if (node.containsFavorite()) {
            Program[] whiteListPrograms = node.getFavorite().getWhiteListPrograms();
            count[0] = whiteListPrograms.length;
            for (Program p : whiteListPrograms) {
                if (p.getDate().equals(currentDate) && !p.isExpired()) {
                    count[1]++;
                }
            }
        }

        for (int i = 0; i < node.getChildCount(); i++) {
            FavoriteNode child = (FavoriteNode) node.getChildAt(i);
            if (child.containsFavorite()) {
                Program[] whiteListPrograms = child.getFavorite().getWhiteListPrograms();
                count[0] += whiteListPrograms.length;

                for (Program p : whiteListPrograms) {
                    if (p.getDate().equals(currentDate) && !p.isExpired()) {
                        count[1]++;
                    }
                }
            } else {
                int[] countReturned = getProgramsCount(child);
                count[0] += countReturned[0];
                count[1] += countReturned[1];
            }
        }
        return count;
    }

    /**
     * Sorts the path from the given node to all leafs alphabetically.
     *
     * @param node The node to sort from.
     * @param comp Comparator for sorting
     * @param title Title of confirmation message dialog
     */
    public void sort(FavoriteNode node, Comparator<FavoriteNode> comp, String title) {
        String msg = mLocalizer.msg("reallySort",
                "Do you really want to sort '{0}'?\n\nThe current order will get lost.", node.toString());
        int result = JOptionPane.showConfirmDialog(UiUtilities.getLastModalChildOf(MainFrame.getInstance()), msg,
                title, JOptionPane.YES_NO_OPTION);
        if (result == JOptionPane.YES_OPTION) {
            sortNodeInternal(node, comp);
        }

        ManageFavoritesDialog.getInstance().favoriteSelectionChanged();
    }

    /**
     * sort favorite nodes (dialog handling must be done by caller)
     * @param node
     * @param comp
     */
    private void sortNodeInternal(FavoriteNode node, Comparator<FavoriteNode> comp) {
        ArrayList<FavoriteNode> childNodes = Collections.list(node.children());
        Collections.sort(childNodes, comp);

        node.removeAllChildren();

        for (FavoriteNode child : childNodes) {
            node.add(child);
            if (child.isDirectoryNode()) {
                sortNodeInternal(child, comp);
            }
        }
    }

    /**
     * Gets the Favorites containing the given receive target in an array.
     *
     * @param target The target to check.
     * @return The Favorites that contains the given receive target in an array.
     */
    public Favorite[] getFavoritesContainingReceiveTarget(ProgramReceiveTarget target) {
        Favorite[] favorites = getFavoriteArr();

        ProgramReceiveTarget[] defaultTargets = FavoritesPlugin.getInstance().getDefaultClientPluginsTargets();

        for (ProgramReceiveTarget defaultTarget : defaultTargets) {
            if (defaultTarget.equals(target)) {
                return favorites;
            }
        }

        ArrayList<Favorite> receiveFavorites = new ArrayList<Favorite>();

        for (Favorite fav : favorites) {
            if (fav.containsReceiveTarget(target)) {
                receiveFavorites.add(fav);
            }
        }

        return receiveFavorites.toArray(new Favorite[receiveFavorites.size()]);
    }

    public void updatePluginTree(final PluginTreeNode topicNode, final ArrayList<Program> allPrograms) {
        updatePluginTree(topicNode, allPrograms, null);
    }

    /**
     * get an array of all favorites containing the given program
     * @param program program to search for
     * @return array of favorites
     * @since 2.7
     */
    public Favorite[] getFavoritesContainingProgram(Program program) {
        ArrayList<Favorite> containing = new ArrayList<Favorite>();

        for (Favorite favorite : getFavoriteArr()) {
            for (Program favProgram : favorite.getPrograms()) {
                if (favProgram.equals(program)) {
                    containing.add(favorite);
                    break;
                }
            }
        }
        return containing.toArray(new Favorite[containing.size()]);
    }

    public boolean isInMultipleFavorites(final Program program) {
        if (mMultiples == null) {
            HashMap<Program, Integer> map = new HashMap<Program, Integer>(2000);
            for (Favorite favorite : getFavoriteArr()) {
                for (Program favProgram : favorite.getPrograms()) {
                    Integer count = map.get(favProgram);
                    if (count == null) {
                        count = 0;
                    }
                    count++;
                    map.put(favProgram, count);
                }
            }
            mMultiples = new ArrayList<Program>();
            for (Entry<Program, Integer> entry : map.entrySet()) {
                if (entry.getValue().intValue() > 1) {
                    mMultiples.add(entry.getKey());
                }
            }
        }
        for (Program dupProgram : mMultiples) {
            if (dupProgram.equals(program)) {
                return true;
            }
        }
        return false;
    }

    public void resetMultiplesCounter() {
        mMultiples = null;
    }
}