001    /* sillyview : a free model-view-controller system for Java
002     * Copyright (C) 2004 T.J. Willis
003     * 
004     * This program is free software; you can redistribute it and/or
005     * modify it under the terms of the GNU General Public License
006     * as published by the Free Software Foundation; either version 2
007     * of the License, or (at your option) any later version.
008     *      
009     * This program is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012     * GNU General Public License for more details.
013     *          
014     * You should have received a copy of the GNU General Public License
015     * along with this program; if not, write to the Free Software
016     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
017     *  
018     * $Header: /cvsroot/sillyview/sillyview/src/net/sourceforge/sillyview/JPanelView.java,v 1.2 2004/05/15 01:58:51 tj_willis Exp $
019     */
020    package net.sourceforge.sillyview;
021    
022    import javax.swing.*;
023    import javax.swing.event.HyperlinkListener;
024    import javax.swing.border.*;
025    import java.util.Map;
026    import java.util.Set;
027    import org.apache.log4j.*;
028    
029    /**
030     * This is a central class in sillyview.  It displays a given WidgetModel
031     * as a JLabel, a JEditorPane, or a HTMLPane.  For implementation reasons
032     * it extends javax.swing.Box, instead of javax.swing.JPanel.
033     *
034     * @author <a href="mailto:tj_willis@users.sourceforge.net">T.J. Willis</a>
035     * @has 0..1 Has - net.sourceforge.sillyview.HTMLPane
036     * @has 0..1 Has - javax.swing.JEditorPane
037     * @has 0..1 Has - javax.swing.JLabel
038     * @version 1.0
039     */
040    public class JPanelView 
041        extends javax.swing.Box 
042        implements WidgetView 
043    {
044       private static final int MIN = 0;
045       private static final int PREF = 1;
046        private Category cat 
047            = Category.getInstance(JPanelView.class.getName());
048        /**
049         * This panel's title.
050         *
051         */
052        protected String title;
053    
054        /**
055         * If data displayed as a JLabel, this is that JLabel.
056         *
057         */
058        protected JLabel lab;
059        /**
060         * If data displayed in a JEditorPane, this is that JEditorPane.
061         *
062         */
063        protected JEditorPane ed;
064        /**
065         * The component that the data is displayed in.
066         *
067         */
068        protected Object comp;
069    
070        /**
071         * The model this view gets its data from.
072         *
073         */
074        protected WidgetModel mod;
075        /**
076         * A token for setting the view's text.
077         *
078         */
079        public static final String TEXT = "<@TEXT>";
080        /**
081         * A token for setting the view's hyperlink listener.
082         *
083         */
084        public static final String HYPERLINK_LISTENER = "<@_HYPERLINK_LISTENER>";
085    
086        /**
087         * If you want data displayed in a JLabel.
088         */
089        public static final int JLABEL = 0;
090        /**
091         * If you want data displayed in a JEditorPane.
092         */
093        public static final int JEDITORPANE = 1;
094        /**
095         * If you want data displayed in a HTMLPane.
096         */
097        public static final int HTMLPANE = 2;
098    
099        /**
100         * Creates a new <code>JPanelView</code> instance backed by the
101         * given WidgetModel and of type JLABEL, JEDITORPANE, or HTMLPANE.
102         *
103         * @param model a <code>WidgetModel</code> value
104         * @param componentType an <code>int</code> value
105         */
106        public JPanelView (final WidgetModel model, final int componentType) {
107            super (BoxLayout.Y_AXIS);
108            //java.awt.BorderLayout b = new java.awt.BorderLayout();
109            //setLayout(b);
110            setDoubleBuffered(true);
111            mod = model;
112    
113            if (componentType == JLABEL) {
114                lab = new JLabel ((String) (model.getCurrentModel ()));
115                comp = lab;
116                add (lab);
117            } else if (componentType == JEDITORPANE) {
118                ed = new JEditorPane ("text/html", null);
119                ed.setText ((String) (model.getCurrentModel ()));
120                ed.setEditable (false);
121                comp = ed;
122                add (ed);           //scroller);
123            } else if (componentType == HTMLPANE) {
124                String x = ((String) (model.getCurrentModel ()));
125                ed = new HTMLPane (x);
126                comp = ed;
127                add (ed);
128            }
129        }
130    
131        /**
132         * Sets this views text.
133         *
134         * @param txt a <code>String</code> value
135         */
136        protected void setText (final String txt) {
137            if (comp == lab) {
138                lab.setText (txt);
139            } else if (comp == ed) {
140                ed.setText (txt);
141            }
142        }
143    
144        /**
145         * Gets this view's text.
146         *
147         * @return a <code>String</code> value
148         */
149        public String getText () {
150            if (comp == ed)
151                return ed.getText ();
152            if (comp == lab)
153                return lab.getText ();
154            return null;
155        }
156    
157        /**
158         * Adds all the name/value pairs and then updates the model.  If
159         * the named token already exists, replace the value.  This is more
160         * efficient than many calls to setToken(), because model.getCurrentModel
161         * is only called once.
162         *
163         */
164        public final void addTokens (final Map < Object, Object > props) {
165            if (props == null) {
166                return;             // FIXME: clear all tokens in model
167            }
168            Set keys = props.keySet ();
169            for (Object k:keys) {
170                String key = k.toString ();
171                mod.setToken (key, props.get (key));
172            }
173            setText (mod.getCurrentModel ().toString ());
174    
175        }
176    
177        /**
178         * Sets the named token to the given value and then recalculates my
179         * text.  Most tokens, other than TITLE and HYPERLINK_LISTENER will
180         * be passed on to the model for handling.
181         *
182         * @param key an <code>Object</code> value
183         * @param value an <code>Object</code> value
184         */
185        public final void setToken (final Object key, Object value) {
186            if (key == null)
187                return;
188    
189            String ti = "";
190            if (value != null)
191                ti = value.toString ();
192    
193            String la = key.toString ();
194            if (TITLE.equals (la)) {
195                title = ti;
196                setTitle (ti);
197            } else if (HYPERLINK_LISTENER.equals (la)) {
198                if (comp == lab) {
199                    //throw new NotSupportedException(001);
200                } else if (comp == ed) {
201                    ed.addHyperlinkListener ((HyperlinkListener) value);
202                }
203                return;
204            }
205            mod.setToken (key, value);
206            setText (mod.getCurrentModel ().toString ());
207        }
208    
209        /**
210         * Gets the named value.  Most values will come from the backing
211         * model.
212         *
213         * @param key an <code>Object</code> value
214         * @return an <code>Object</code> value
215         */
216        public final Object getValue (final Object key) {
217            if (key == null)
218                return null;
219            String la = key.toString ();
220            if (TITLE.equals (la))
221                return title;
222    
223            return mod.getValue (key);
224        }
225    
226        /**
227         * Sets the panel's title to the given text, providing a titled border.
228         *
229         * @param val a <code>String</code> value
230         */
231        protected final void setTitle (final String val) {
232            title = val;
233            Border etched = BorderFactory.createEtchedBorder ();
234            etched = BorderFactory.createTitledBorder (etched, val);
235            setBorder (etched);
236        }
237    
238        /**
239         * Returns the backing model.
240         *
241         * @return a <code>WidgetModel</code> value
242         */
243        public final WidgetModel getModel () {
244            return mod;
245        }
246    
247        /**
248         * Sets the backing model.
249         *
250         * @param newModel a <code>WidgetModel</code> value
251         */
252        public final void setModel (final WidgetModel newModel) {
253            mod = newModel;
254        }
255    
256        /**
257         * Sets the preferred size of this panel as well as the view component.
258         *
259         * @param size a <code>java.awt.Dimension</code> value
260         */
261        public void setPreferredSize (java.awt.Dimension size) {
262            super.setPreferredSize (size);
263            resizeComponent(PREF,size);
264        }
265    
266      
267        private void resizeComponent(int which, java.awt.Dimension size){
268          try {
269            if (comp == null || !(comp instanceof JComponent))
270                return;
271            JComponent c = (JComponent) comp;
272            if(which==PREF)
273               c.setPreferredSize (size);
274            else
275               c.setMinimumSize( size);
276            validate ();
277          } catch (Exception ex) {
278              cat.warn("resize exception : ",ex);
279          }
280    
281        }
282    
283    
284        /**
285         * Sets the minimum size of this panel as well as the view component.
286         *
287         * @param size a <code>java.awt.Dimension</code> value
288         */
289        public void setMinimumSize (java.awt.Dimension size) {
290            super.setMinimumSize (size);
291            resizeComponent(MIN,size);
292        }
293    
294        /**
295         * If the view component is a HTMLPane, will set its autodump property.
296         *
297         * @param b a <code>boolean</code> value
298         */
299        public void setAutoDump(boolean b){
300           if(ed!=null && ed instanceof HTMLPane){
301              HTMLPane h = (HTMLPane) ed;
302              h.setAutoDump(b);
303           }
304    
305       }
306    }