001package hirondelle.stocks.portfolio;
002
003import java.util.Observable;
004import java.util.*;
005import hirondelle.stocks.util.Args;
006import hirondelle.stocks.quotes.Stock;
007
008/**
009 * The central abstraction of this package, representing the current selection of 
010 * stocks of interest to the end user 
011 * (a {@link hirondelle.stocks.portfolio.Portfolio}).
012 * 
013 * <P><tt>CurrentPortfolio</tt> may be used as an example implementation for any
014 * application which edits one item at a time.
015 * 
016 * <p>The {@link #isUntitled} and {@link #getNeedsSave} properties are particularly
017 * significant. They influence the file menu actions. For example, a
018 * <tt>CurrentPortfolio</tt> for which {@link #isUntitled} is true cannot be deleted.
019 * 
020 * <p><tt>CurrentPortfolio</tt> is an {@link java.util.Observable}. To minimize spurious
021 * updates, related {@link java.util.Observer} objects need to call
022 * {@link java.util.Observable#notifyObservers()} explicitly. This is important in this
023 * application, since quotes are fetched from the web each time the current portfolio is
024 * updated, and this is a relatively expensive operation.
025 */
026public final class CurrentPortfolio extends Observable {
027
028  /**
029   * Constructor.
030   *  
031   * @param aPortfolio is the set of stocks of current interest to the user; no 
032   * defensive copy is made of <tt>aPortfolio</tt>.
033   * @param aNeedsSave is true only if this <tt>CurrentPortfolio</tt> 
034   * has been edited by the end user, and these edits have not yet been saved.
035   */
036  public CurrentPortfolio(Portfolio aPortfolio, NeedsSave aNeedsSave) {
037    Args.checkForNull(aPortfolio);
038    fPortfolio = aPortfolio;
039    fNeedsSave = aNeedsSave.getValue();
040    // upon construction of the main window, an update is desired in order to
041    // synch the gui with the current portfolio. This update is called explicitly.
042    // Thus, setChanged needs to be set here, since it's default value is false.
043    setChanged();
044  }
045
046  /**
047  * Enumeration for the two states of <tt>aNeedsSave</tt> passed to the constructor.
048  * Use of an enumeration forces the caller to create a constructor call which has
049  * high clarity.
050  */
051  public enum NeedsSave {
052    TRUE(true),
053    FALSE(false);
054    boolean getValue() {
055      return fToggle;
056    }
057    private final boolean fToggle;
058    private NeedsSave(boolean aToggle) {
059      fToggle = aToggle;
060    }
061  }
062
063  /**
064   * Revert to an untitled <tt>Portfolio</tt> which does not need a save.
065   */
066  public void clear() {
067    setPortfolio(Portfolio.getUntitledPortfolio());
068    setNeedsSave(false);
069  }
070
071  /**
072   * Return <tt>true</tt> only if the current <tt>Portfolio</tt> has never been
073   * saved under a user-specified name, neither in this session, nor in any other. Such a
074   * <tt>Portfolio</tt> appears as untitled in the display.
075   */
076  public boolean isUntitled() {
077    return fPortfolio.isUntitled();
078  }
079
080  /**
081   * Return the {@link Portfolio} of current interest to the user.
082   */
083  public Portfolio getPortfolio() {
084    return fPortfolio;
085  }
086
087  /**
088   * Change the {@link Portfolio} of current interest to the user.
089   */
090  public void setPortfolio(Portfolio aPortfolio) {
091    Args.checkForNull(aPortfolio);
092    fPortfolio = aPortfolio;
093    setChanged();
094  }
095
096  /**
097   * Return the name of this <tt>CurrentPortfolio</tt>.
098   */
099  public String getName() {
100    return fPortfolio.getName();
101  }
102
103  /**
104   * Change the name of this <tt>CurrentPortfolio</tt>.
105   * @param aName has the same conditions as 
106   * {@link hirondelle.stocks.portfolio.Portfolio#setName(String)}.
107   */
108  public void setName(String aName) {
109    fPortfolio.setName(aName);
110    setChanged();
111  }
112
113  /**
114   * Return the {@link hirondelle.stocks.quotes.Stock} objects in this
115   * <tt>CurrentPortfolio</tt>.
116   */
117  public Set<Stock> getStocks() {
118    return fPortfolio.getStocks();
119  }
120
121  /**
122   * Change the stocks in this <tt>CurrentPortfolio</tt>.
123   * @param aStocks has the same conditions as
124   * {@link hirondelle.stocks.portfolio.Portfolio#setStocks(Set)}
125   */
126  public void setStocks(Set<Stock> aStocks) {
127    fPortfolio.setStocks(aStocks);
128    setChanged();
129  }
130
131  /**
132   * Return <tt>true</tt> only if this <tt>CurrentPortfolio</tt> has unsaved
133   * edits.
134   */
135  public boolean getNeedsSave() {
136    return fNeedsSave;
137  }
138
139  /**
140   * Indicate that this <tt>CurrentPortfolio</tt> either does or does not have any
141   * unsaved edits.
142   */
143  public void setNeedsSave(boolean aNeedsSave) {
144    fNeedsSave = aNeedsSave;
145    setChanged();
146  }
147
148  // PRIVATE 
149  private Portfolio fPortfolio;
150  private boolean fNeedsSave;
151}