JMoneyPlugin.java :  » ERP-CRM-Financial » jmoney » net » sf » jmoney » Java Open Source

Java Open Source » ERP CRM Financial » jmoney 
jmoney » net » sf » jmoney » JMoneyPlugin.java
/*
 *
 *  JMoney - A Personal Finance Manager
 *  Copyright (c) 2004 Nigel Westbury <westbury@users.sourceforge.net>
 *
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

package net.sf.jmoney;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Vector;

import net.sf.jmoney.model2.Currency;
import net.sf.jmoney.model2.CurrencyInfo;
import net.sf.jmoney.model2.CurrentSessionChangeListener;
import net.sf.jmoney.model2.DatastoreManager;
import net.sf.jmoney.model2.ISessionChangeFirer;
import net.sf.jmoney.model2.ISessionFactory;
import net.sf.jmoney.model2.Propagator;
import net.sf.jmoney.model2.PropertySet;
import net.sf.jmoney.model2.Session;
import net.sf.jmoney.model2.SessionChangeFirerListener;
import net.sf.jmoney.model2.SessionChangeListener;
import net.sf.jmoney.views.TreeNode;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

/**
 * The main plugin class to be used in the desktop.
 */
public class JMoneyPlugin extends AbstractUIPlugin {

    public static final String PLUGIN_ID = "net.sf.jmoney";

    public static final boolean DEBUG = "true".equalsIgnoreCase(Platform.getDebugOption("net.sf.jmoney/debug"));

  //The shared instance.
  private static JMoneyPlugin plugin;
  //Resource bundle.
  private ResourceBundle resourceBundle;
  
    private DatastoreManager sessionManager = null;

    private Vector<CurrentSessionChangeListener> sessionChangeListeners = new Vector<CurrentSessionChangeListener>();
    
    // Create a listener that listens for changes to the new session.
    private SessionChangeFirerListener sessionChangeFirerListener =
      new SessionChangeFirerListener() {
        public void sessionChanged(ISessionChangeFirer firer) {
              if (!sessionChangeListeners.isEmpty()) {
                // Take a copy of the listener list.  By doing this we
                // allow listeners to safely add or remove listeners.
                SessionChangeListener listenerArray[] = new SessionChangeListener[sessionChangeListeners.size()];
                sessionChangeListeners.copyInto(listenerArray);
                for (SessionChangeListener listener: listenerArray) {
                  firer.fire(listener);
                }
              }
          
        }
      };

    /**
   * The constructor.
   */
  public JMoneyPlugin() {
    super();
    plugin = this;
    try {
      resourceBundle   = ResourceBundle.getBundle("net.sf.jmoney.resources.Language");
    } catch (MissingResourceException x) {
      resourceBundle = null;
    }
  }

  /**
   * This method is called upon plug-in activation
   */
  @Override
  public void start(BundleContext context) throws Exception {
    super.start(context);
    
    PropertySet.init();
    Propagator.init();
    TreeNode.init();
  }

  /**
   * This method is called when the plug-in is stopped
   */
  @Override
  public void stop(BundleContext context) throws Exception {
    super.stop(context);
  }

  /**
   * Returns the shared instance.
   */
  public static JMoneyPlugin getDefault() {
    return plugin;
  }

  /**
   * Returns the string from the plugin's resource bundle,
   * or 'key' if not found.
   */
  public static String getResourceString(String key) {
    ResourceBundle bundle = JMoneyPlugin.getDefault().getResourceBundle();
    try {
      return (bundle != null) ? bundle.getString(key) : key;
    } catch (MissingResourceException e) {
      return key;
    }
  }

  public static Image createImage(String name) {
//    String iconPath = "icons/";
    String iconPath = "";
    try {
      URL installURL = getDefault().getBundle().getEntry("/");
      URL url = new URL(installURL, iconPath + name);
      return ImageDescriptor.createFromURL(url).createImage();
    } catch (MalformedURLException e) {
      // should not happen
      return ImageDescriptor.getMissingImageDescriptor().createImage();
    }
  }

  public static ImageDescriptor createImageDescriptor(String name) {
    // Make above call this, or remove above
//    String iconPath = "icons/";
    String iconPath = "";
    try {
      URL installURL = getDefault().getBundle().getEntry("/");
      URL url = new URL(installURL, iconPath + name);
      return ImageDescriptor.createFromURL(url);
    } catch (MalformedURLException e) {
      // should not happen
      return ImageDescriptor.getMissingImageDescriptor();
    }
  }

  /**
   * Log status to log the of this plug-in.
   */  
  public static void log(IStatus status) {
    getDefault().getLog().log(status);
  }

  /**
   * Log exception to the log of this plug-in.
   * 
   * @param e Exception to log
   */
  public static void log(Throwable e) {
    log(new Status(IStatus.ERROR, JMoneyPlugin.PLUGIN_ID, IStatus.ERROR, "Internal errror", e));
  }

  /**
   * Returns the plugin's resource bundle,
   */
  public ResourceBundle getResourceBundle() {
    return resourceBundle;
  }
  
    public DatastoreManager getSessionManager() {
        return sessionManager;
    }
   
    /**
   * Saves the old session.
   * Returns false if canceled by user or the save fails.
   */
  public boolean saveOldSession(IWorkbenchWindow window) {
    if (sessionManager == null) {
      return true;
    } else {
      return sessionManager.canClose(window);
    }
  }
  
  // Helper method
    // TODO: see if we really need this method.
    public Session getSession() {
        return sessionManager == null 
      ? null 
      : sessionManager.getSession();
    }
    
    /**
     * Sets the Session object.  The session object contains the accounting
     * data so this method will replace the accounting data in the framework
     * with a new set of accounting data.  This method is normally called
     * only by plug-ins that implement a datastore when accounting data
     * is loaded.
     *
     * To avoid doing too much work and user input before setting the new 
     * session, only to find that the
     * user does not want to close the previous session, plug-in actions
     * that expect to set a new session should call canClose on the previous
     * session before preparing the new session.  It is the caller's
     * responsibility to ensure that
     * both canClose() and close() are called on the previous session.
     * This method will not close any previously set session.
     */
    public void setSessionManager(DatastoreManager newSessionManager) {
        // It is up to the caller to ensure that the previous session
        // has been closed.

        if (sessionManager == newSessionManager)
            return;
        DatastoreManager oldSessionManager = sessionManager;
        sessionManager = newSessionManager;
        
      /*
     * JMoney depends on having at least one currency, which must also be
     * set as the default currency. If there is no default currency then
     * this must be a new datastore and we must set a default currency.
     */
        if (newSessionManager != null) {
          if (getSession().getDefaultCurrency() == null) {
            initSystemCurrency(getSession());
          }
        }

        // It is possible, tho I can't think why, that a listener who
        // we tell of a change in the current session will modify either
        // the old or the new session.
        // The correct way of handling this is:
        // - if a change is made to the old session then only those
        //   listeners that have not been told of the change of session
        //   should be told.
        // - if a change is made to the new session then only those
        //   listeners that have already been told of the change of session
        //   (including the listener that made the change) should be told
        //   of the change.
        // This code handles this correctly.
        
        // We do not support the scenario where a listener replaces the
        // session itself while being notified of a change in the session.
        // Any attempt to do this will cause an exception to be thrown.
        // TODO: Throw this exception.
        
        // If a listener adds a further listener then the correct
        // way of handling this is for the new listener to start
        // recieving change notifications immediately.  This includes
        // changes made to the session by the listener that had added
        // the new listener and also changes made by other listeners that
        // had not, at the time the new listener had been created,
        // been notified of the change in the current session.

        // TODO: Implement the above or decide on a design and what
        // restrictions we impose.
        
        if (!sessionChangeListeners.isEmpty()) {
          // Take a copy of the listener list.  By doing this we
          // allow listeners to safely add or remove listeners.
          CurrentSessionChangeListener listenerArray[] = new CurrentSessionChangeListener[sessionChangeListeners.size()];
          sessionChangeListeners.copyInto(listenerArray);
          for (int i = 0; i < listenerArray.length; i++) {
            listenerArray[i].sessionReplaced(
                oldSessionManager == null ? null : oldSessionManager.getSession(), 
                newSessionManager == null ? null : newSessionManager.getSession()
            );
          }
        }
        
        // Stop listening to the old session and start listening to the
        // new session for changes within the session.
        if (oldSessionManager != null) {
          oldSessionManager.removeSessionChangeFirerListener(sessionChangeFirerListener);
        }
        if (newSessionManager != null) {
          newSessionManager.addSessionChangeFirerListener(sessionChangeFirerListener);
        }
  }

    /**
     * Get the corresponding ISO currency for "code". If "session" already
     * contains such a currency this currency is returned. Otherwise, we
     * check our list of ISO 4217 currencies and we create a new currency
     * instance for "session".
     * 
     * @param session Session object which will contain the currency
     * @param code ISO currency code
     * @return Currency for "code"
     */
    public static Currency getIsoCurrency(Session session, String code) {
        // Check if the currency already exists for this session.
        Currency result = session.getCurrencyForCode(code);
        if (result != null) return result;

        // Find the currency in our list of ISO 4217 currencies
        ResourceBundle res = ResourceBundle.getBundle("net.sf.jmoney.resources.Currency");
        byte decimals = 2;
        try {
            InputStream in = JMoneyPlugin.class.getResourceAsStream("Currencies.txt");
            BufferedReader buffer = new BufferedReader(new InputStreamReader(in));
            for (String line = buffer.readLine(); line != null; line = buffer.readLine()) {
                if (line.substring(0, 3).equals(code)) {
                  // The Currencies.txt file does not contain the number of decimals
                  // for every currency.  If no number is in the file then a StringIndexOutOfBoundsException
                  // will be thrown and we assume two decimal places.
                  try {
                    decimals = Byte.parseByte(line.substring(4, 5));
                  } catch (StringIndexOutOfBoundsException e) {
                    decimals = 2;
                  }
                }
            }
        } catch (IOException ioex) {
            log(ioex);
        } catch (NumberFormatException nfex) {
            log(nfex);
        }

        result = session.createCommodity(CurrencyInfo.getPropertySet());
        result.setCode(code);
        result.setName(res.getString(code));
        result.setDecimals(decimals);

        return result;
    }

    /**
     * Whenever a new session is created, JMoney will set a single initial
     * currency.  The currency is taken from our list of ISO 4217
     * currencies and chosen using information from the default locale.
     * This currency is also set as the default currency.
     * <P>
     * By doing this, we minimize the number of steps that a new JMoney
     * user must take to get started.  If a user only ever uses a single
     * currency then the user may never have to worry about currencies
     * and may never see a currency selection control.
     * 
     * @param session
     */
  public static void initSystemCurrency(Session session) {
        Locale defaultLocale = Locale.getDefault();
        NumberFormat format = NumberFormat.getCurrencyInstance(defaultLocale);
        String code = format.getCurrency().getCurrencyCode();
        Currency currency = getIsoCurrency(session, code);
        if (currency == null) {
          // JMoney depends on a default currency
          currency = getIsoCurrency(session, "USD");
        }
        
        /*
         * Note that although we are modifying the datastore,
         * we do not make this an undoable operation.  The user
         * did not set this currency and the user should not be
         * able to undo it.
         */
        session.setDefaultCurrency(currency);
    }

  /**
   * Adds a change listener.
   * <P>
   * The listener is active only for as long as the given control exists.  When the
   * given control is disposed, the listener is removed and will receive no more
   * notifications.
   * <P>
   * This method is generally used when a listener is used to update contents in a
   * control.  Typically multiple controls are updated by a listener and the parent
   * composite control is passed to this method.
   * 
   * @param listener
   * @param control
   */
  public void addSessionChangeListener(final CurrentSessionChangeListener listener, Control control) {
        sessionChangeListeners.add(listener);
        
    // Remove the listener when the given control is disposed.
    control.addDisposeListener(new DisposeListener() {
      public void widgetDisposed(DisposeEvent e) {
        sessionChangeListeners.remove(listener);
      }
    });
    }

    // Preferences
    
    /**
     * Get the format to be used for dates.  This format is
     * compatible with the VerySimpleDateFormat class.
     * The format is read from the preference store.
     */
    public String getDateFormat() {
      /*
     * The following line cannot return a null value, even if the user did
     * not set a value, because a default value is set. The default value is
     * set by by JMoneyPreferenceInitializer (an extension to the
     * org.eclipse.core.runtime.preferences extension point).
     */
      return getPreferenceStore().getString("dateFormat");
    }

  /**
   * Given a memento containing the data needed to open a session,
   * return the session.  If the session is already open
   * then return the session, otherwise the session is opened
   * by this method and returned.
   *  
   * @param memento
   * @return
   */
  public static Session openSession(IMemento memento) {
    if (memento != null) {
      // This is a kludge.  Only one session can be open at a time,
      // therefore all views that need a session will save the same
      // data in the session memento.  Therefore, if a session is open,
      // just return that.  We know it is the right session.
      if (getDefault().getSession() != null) {
        return getDefault().getSession();
      }
      
      String factoryId = memento.getString("currentSessionFactoryId"); 
      if (factoryId != null && factoryId.length() != 0) {
        // Search for the factory.
        IExtensionRegistry registry = Platform.getExtensionRegistry();
        for (IConfigurationElement element: registry.getConfigurationElementsFor("org.eclipse.ui.elementFactories")) {
          if (element.getName().equals("factory")) {
            if (element.getAttribute("id").equals(factoryId)) {
              try {
                ISessionFactory listener = (ISessionFactory)element.createExecutableExtension("class");

                // Create and initialize the session object from 
                // the data stored in the memento.
                listener.openSession(memento.getChild("currentSession"));
                return getDefault().getSession();
              } catch (CoreException e) {
                // Could not create the factory given by the 'class' attribute
                // Log the error and start JMoney with no open session.
                e.printStackTrace();
              }
              break;
            }
          }
        }
      }
    }
    
      return null;
  }

  /**
   * Helper method to compare two objects.  Either or both
   * the objects may be null.  If both objects are null,
   * they are considered equal.
   * 
   * @param object
   * @param object2
   * @return
   */
  public static boolean areEqual(Object object1, Object object2) {
    return (object1 == null)
      ? (object2 == null)
          : object1.equals(object2);
  }
}
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.