MainModule.java :  » Music » jukes » com » melloware » jukes » gui » tool » Java Open Source

Java Open Source » Music » jukes 
jukes » com » melloware » jukes » gui » tool » MainModule.java
package com.melloware.jukes.gui.tool;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.prefs.Preferences;

import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.jgoodies.binding.beans.Model;
import com.jgoodies.uif.application.Application;
import com.jgoodies.uif.util.ResourceUtils;
import com.jgoodies.uifextras.convenience.SetupManager;
import com.melloware.jukes.db.orm.AbstractJukesObject;
import com.melloware.jukes.db.orm.Artist;
import com.melloware.jukes.db.orm.Catalog;
import com.melloware.jukes.db.orm.Disc;
import com.melloware.jukes.db.orm.Track;
import com.melloware.jukes.file.image.ImageFactory;
import com.melloware.jukes.file.tag.MusicTag;
import com.melloware.jukes.gui.view.MainFrame;
import com.melloware.jukes.gui.view.node.AbstractTreeNode;
import com.melloware.jukes.gui.view.node.ArtistNode;
import com.melloware.jukes.gui.view.node.DiscNode;
import com.melloware.jukes.gui.view.node.NavigationNode;
import com.melloware.jukes.gui.view.node.RootNode;
import com.melloware.jukes.gui.view.node.TrackNode;
import com.melloware.jukes.util.MessageUtil;

/**
 * Provides bound bean properties for the catalog, navigation tree, navigation
 * tree selection, selection type. Refers to the presentation settings and a
 * submodule for the dynamic help.
 * <p>
 * Copyright (c) 1999-2007 Melloware, Inc. <http://www.melloware.com>
 * @author Emil A. Lefkof III <info@melloware.com>
 * @version 4.0 AZ - some modifications 2009
 * @see Settings
 * @see DynamicHelpModule
 */
public final class MainModule extends Model {

   private static final Log LOG = LogFactory.getLog(MainModule.class);

   public static final String PROPERTYNAME_CATALOG = "catalog";
   public static final String PROPERTYNAME_HIGHLIGHT = "highlight";
   public static final String PROPERTYNAME_SELECTION = "selection";
   public static final String PROPERTYNAME_SELECTION_TYPE = "selectionType";
   public static final String PROPERTYNAME_NAVIGATION_TREE_MODEL = "navigationTreeModel";

   /**
    * Refers to the submodule for the UI-related settings.
    * @see #getSettings()
    */
   public static final Settings SETTINGS = new Settings();

   /**
    * Holds the current catalog.
    * @see #getCatalog()
    * @see #setCatalog(Catalog)
    */
   private Catalog catalog;

   /**
    * Holds the class of the current selection.
    * @see #getSelection()
    * @see #getSelectionType()
    */
   private Class selectionType;

   /**
    * Holds the node that refers to the current selection. Used to report a
    * potential change to its hosting tree model when the selection changes.
    * This is because the node's label may have changed as part of the editor
    * change.
    * <p>
    * This is a poor workaround that is based on the weak assumumption that this
    * class's tree selection listener is the first to know about the node
    * change.
    * <p>
    */
   private NavigationNode selectedNode;

   /**
    * Holds the current selection, an instance of Model.
    * @see #getSelection()
    * @see #getSelectionType()
    */
   private Object selection;

   /**
    * Holds the model for the navigation tree. It changes every time this
    * module's catalog changes.
    * @see #getNavigationTreeModel()
    * @see #getNavigationTreeSelectionModel()
    */
   private TreeModel navigationTreeModel;

   /**
    * Refers to the single selection model for the navigation tree. The
    * selection is reset if the navigation tree model changes.
    * @see #getNavigationTreeSelectionModel()
    * @see #getNavigationTreeModel()
    */
   private final TreeSelectionModel navigationTreeSelectionModel = new DefaultTreeSelectionModel();

   /**
    * Constructs a <code>MainModule</code> that has no catalog set, no selection
    * and no tree model.
    */
   public MainModule() {
      LOG.debug("MainModule created.");
      restoreFromFile(); // AZ
      restoreState();
      MusicTag.setSettings(SETTINGS); // AZ
      ImageFactory.setSettings(SETTINGS);// AZ
      Catalog.setSettings(SETTINGS);// AZ
   }

   /**
    * Returns the current catalog.
    * @return the current catalog.
    */
   public Catalog getCatalog() {
      return catalog;
   }

   /**
    * Returns the tree model for the navigation tree.
    * @return the tree model for the navigation tree.
    */
   public TreeModel getNavigationTreeModel() {
      return navigationTreeModel;
   }

   /**
    * Returns the fixed selection model for the navigation tree.
    * @return the fixed selection model for the navigation tree.
    */
   public TreeSelectionModel getNavigationTreeSelectionModel() {
      return navigationTreeSelectionModel;
   }

   /**
    * Gets the selectedNode.
    * <p>
    * @return Returns the selectedNode.
    */
   public NavigationNode getSelectedNode() {
      return this.selectedNode;
   }

   /**
    * Returns the current selection, a domain object. This selection will be
    * updated if the selection in the navigation tree changes. During the
    * transition from one tree selection to another this value may hold the old
    * or new selection.
    * @return the domain object selected in the navigation tree.
    * @see #getSelectionType()
    */
   public Object getSelection() {
      return selection;
   }

   /**
    * Returns the class of the selected domain object.
    * @return the class of the selected domain object.
    * @see #getSelection()
    */
   public Class getSelectionType() {
      return selectionType;
   }

   /**
    * Sets a new catalog.
    * @param newCatalog the catalog to set
    * @throws NullPointerException if the new catalog is null
    */
   public void setCatalog(final Catalog newCatalog) {
      if (newCatalog == null) {
         throw new IllegalArgumentException("The catalog must not be null.");
      }

      final Catalog oldCatalog = getCatalog();
      catalog = newCatalog;
      firePropertyChange(PROPERTYNAME_CATALOG, oldCatalog, newCatalog);
      setNavigationTreeModel(createNavigationTreeModel(newCatalog));

   }

   /**
    * Checks and answers whether the catalog's file path is valid.
    * @return true if the catalog's file path is valid.
    */
   public boolean isCatalogFilePathValid() {
      return false;
   }

   /**
    * Checks and answers if a catalog is loaded.
    * @return true if a catalog is loaded.
    */
   public boolean hasCatalog() {
      return getCatalog() != null;
   }

   /**
    * Refreshes the currently selected tree node.
    * <p>
    * @param domainObject the domain object may be useful
    * @param operation NODE_INSERTED, NODE_DELETED, NODE_CHANGED
    */
   public void refreshSelection(final Object domainObject, final String operation) {
      if (selectedNode == null) {
         return;
      }
      final DefaultTreeModel treeModel = ((DefaultTreeModel) getNavigationTreeModel());
      if (Resources.NODE_CHANGED.equals(operation)) {
         treeModel.nodeChanged(selectedNode);
         LOG.debug("Tree Node changed.");
      } else if (Resources.NODE_DELETED.equals(operation)) {
         final TreeNode parent = selectedNode.getParent();
         if (parent != null) {
            LOG.debug("Tree Node Deleted");
            treeModel.removeNodeFromParent((DefaultMutableTreeNode) selectedNode);
            setSelectedNode((AbstractTreeNode) parent);
         }
      }
   }

   /**
    * Refreshes the tree node from the database.
    * <p>
    * @throws NullPointerException if the new catalog is null
    */
   public void refreshTree() {
      setCatalog(new Catalog(SETTINGS.getFilter()));
      firePropertyChange(PROPERTYNAME_SELECTION, selection, null);
   }

   /**
    * AZ Refreshes the tree node from the database and go to specified selection
    * <p>
    * @throws NullPointerException if the new catalog is null
    */
   public void refreshTree(Object selectedObject) {
      setCatalog(new Catalog(SETTINGS.getFilter()));
      firePropertyChange(PROPERTYNAME_SELECTION, selection, selectedObject);
      selectNodeInTree(selectedObject);
   }

   /**
    * Restores the application state from the user preferences.
    */
   public void restoreState() {
      SETTINGS.restoreFrom(Application.getUserPreferences());
   }

   /**
    * Finds the selection in the tree and expands the node and sets the editor.
    * @param newSelection the selection to set
    * @see #getSelection()
    */
   public void selectNodeInTree(final Object newSelection) {
      final AbstractJukesObject selection = (AbstractJukesObject) newSelection;
      AbstractTreeNode node = null;
      String artistName = null;
      String discName = null;
      String trackName = null;
      if (selection instanceof Artist) {
         artistName = selection.getName();
      } else if (selection instanceof Disc) {
         final Disc disc = (Disc) selection;
         artistName = disc.getArtist().getName();
         discName = selection.getName();
      } else if (selection instanceof Track) {
         final Track track = (Track) selection;
         artistName = track.getDisc().getArtist().getName();
         discName = track.getDisc().getName();
         trackName = selection.getName();
      }

      final DefaultTreeModel treeModel = ((DefaultTreeModel) navigationTreeModel);
      final AbstractTreeNode root = (AbstractTreeNode) treeModel.getRoot();

      // loop through the artists
      ArtistNode artistNode = null;
      if (StringUtils.isNotBlank(artistName)) {
         final Enumeration artistEnum = root.children();
         while (artistEnum.hasMoreElements()) {
            artistNode = (ArtistNode) artistEnum.nextElement();
            if (StringUtils.equalsIgnoreCase(artistNode.toString(), artistName)) {
               node = artistNode;
               break; // found it
            }
         }
      }

      // now get the disc
      DiscNode discNode = null;
      if ((StringUtils.isNotBlank(discName)) && (artistNode != null)) {
         final Enumeration discEnum = artistNode.children();
         while (discEnum.hasMoreElements()) {
            discNode = (DiscNode) discEnum.nextElement();
            if (StringUtils.equalsIgnoreCase(discNode.toString(), discName)) {
               node = discNode;
               break; // found it
            }
         }
      }

      // now get the track
      TrackNode trackNode = null;
      if ((StringUtils.isNotBlank(trackName)) && (discNode != null)) {
         final Enumeration trackEnum = discNode.children();
         while (trackEnum.hasMoreElements()) {
            trackNode = (TrackNode) trackEnum.nextElement();
            if (StringUtils.equalsIgnoreCase(trackNode.toString(), trackName)) {
               node = trackNode;
               break; // found it
            }
         }
      }

      if (node != null) {
         // tree node found
         setSelectedNode(node);

         // fire this property change to tell the tree to select the node
         firePropertyChange(PROPERTYNAME_HIGHLIGHT, null, "Highlight");
      }
   }

   /**
    * Stores the application state to the user preferences.
    */
   public void storeState() {
      final Preferences prefs = Application.getUserPreferences();
      SETTINGS.storeIn(prefs);
      SetupManager.incrementUsageCounter();
   }

   /**
    * Sets a new tree model for the navigation tree.
    * <p>
    * @param newModel the new tree model to set
    */
   private void setNavigationTreeModel(final TreeModel newModel) {
      final TreeModel oldModel = getNavigationTreeModel();
      navigationTreeModel = newModel;
      firePropertyChange(PROPERTYNAME_NAVIGATION_TREE_MODEL, oldModel, newModel);
   }

   /**
    * Sets the selection and reports the previously selected node as changed.
    * <p>
    * <strong>Note:</strong> This code requires a special order. It assumes that
    * domain changes happen when the selection changes.
    * <p>
    * @param newSelectedNode the new node selection
    */
   private void setSelectedNode(final NavigationNode newSelectedNode) {
      final NavigationNode oldSelectedNode = selectedNode;
      selectedNode = newSelectedNode;
      setSelection(newSelectedNode.getModel());
      ((DefaultTreeModel) getNavigationTreeModel()).nodeChanged(oldSelectedNode);
   }

   /**
    * Sets a new domain object as selection. This method is invoked by the
    * NavigationTreeSelectionChangeHandler that observes changes in the
    * selection of the navigation tree.
    * @param newSelection the selection to set
    * @see #getSelection()
    */
   private void setSelection(final Object newSelection) {
      final Object oldSelection = getSelection();
      selection = newSelection;
      setSelectionType(newSelection.getClass());
      firePropertyChange(PROPERTYNAME_SELECTION, oldSelection, newSelection);
   }

   /**
    * Sets a new selection type. This method is invoked in
    * <code>#setSelection</code> with the class of the new selection.
    * @param newSelectionType the selection type to set
    * @see #getSelectionType()
    */
   private void setSelectionType(final Class newSelectionType) {
      final Class oldSelectionType = getSelectionType();
      selectionType = newSelectionType;
      if (equals(oldSelectionType, newSelectionType)) {
         return;
      }

      firePropertyChange(PROPERTYNAME_SELECTION_TYPE, oldSelectionType, newSelectionType);
   }

   /**
    * Creates and returns a tree model for the given catalog. Constructs a
    * <code>RootNode</code> with the catalog and returns a
    * <code>DefaultTreeModel</code> with this root.
    * @return a TreeModel for the given catalog
    */
   private TreeModel createNavigationTreeModel(final Catalog catalog) {
      final RootNode rootNode = new RootNode(catalog);
      rootNode.setSettings(SETTINGS);
      final DefaultTreeModel model = new DefaultTreeModel(rootNode);
      navigationTreeSelectionModel.setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
      navigationTreeSelectionModel.addTreeSelectionListener(new NavigationTreeSelectionChangeHandler());
      return model;
   }

   // Listens to changes in the navigation tree node selection
   // and updates the selection.
   private class NavigationTreeSelectionChangeHandler implements TreeSelectionListener {

      /**
       * The selected node in the navigation tree has changed. Updates this
       * module's selected domain object and in turn the selection type.
       * <p>
       * Does nothing if the new tree selection is <code>null</code>.
       * @param evt the event that describes the change
       */
      public void valueChanged(final TreeSelectionEvent evt) {
         final TreePath path = evt.getPath();
         final NavigationNode aSelectedNode = (NavigationNode) path.getLastPathComponent();
         if (aSelectedNode != null) {
            setSelectedNode(aSelectedNode);
         }
      }

   }

   // AZ
   // read preferences from file jukes.xml
   private void restoreFromFile() {
      LOG.info("Read Preferences from jukes.xml");
      final String errorMessage = ResourceUtils.getString("messages.ErrorReadPrefsFile");
      final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
      final File file = new File(FilenameUtils.normalizeNoEndSeparator(SystemUtils.USER_DIR
               + SystemUtils.FILE_SEPARATOR + "jukes.xml"));
      // now try and import the preferences from a file
      if (file.exists()) {
         try {
            final FileInputStream stream = new FileInputStream(file);
            Preferences.importPreferences(stream);
         } catch (IOException ex) {
            MessageUtil.showError(mainFrame, errorMessage); // AZ
            LOG.error(errorMessage + ex.getMessage(), ex);
         } catch (Exception ex) {
            MessageUtil.showError(mainFrame, errorMessage); // AZ
            LOG.error(errorMessage, ex);
         }
      }
   }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.