001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: UIChangeManager.java,v $
023   Revision 1.12  2004/05/12 18:51:35  markl
024   comment block updates
025
026   Revision 1.11  2003/04/30 04:36:17  markl
027   Add default frame icon property.
028
029   Revision 1.10  2003/01/19 09:50:54  markl
030   Javadoc & comment header updates.
031
032   Revision 1.9  2001/03/12 09:28:01  markl
033   Source code and Javadoc cleanup.
034
035   Revision 1.8  1999/07/29 04:34:17  markl
036   Minor tweaks.
037
038   Revision 1.7  1999/06/08 06:47:22  markl
039   Added import statement.
040
041   Revision 1.6  1999/05/15 08:16:14  markl
042   bug fix
043
044   Revision 1.5  1999/05/10 08:59:17  markl
045   Changed param type on setColorTheme(), fixed default texture filename.
046
047   Revision 1.4  1999/04/26 09:27:32  markl
048   Added method for setting theme.
049
050   Revision 1.3  1999/04/25 04:12:41  markl
051   Changes to support solid backgrounds in addition to textures.
052
053   Revision 1.2  1999/01/10 03:01:37  markl
054   added GPL header & RCS tag
055   ----------------------------------------------------------------------------
056*/
057
058package kiwi.ui;
059
060import java.awt.*;
061import java.util.*;
062import java.beans.*;
063import javax.swing.*;
064import javax.swing.UIManager.LookAndFeelInfo;
065import javax.swing.plaf.metal.*;
066
067import kiwi.event.*;
068import kiwi.io.*;
069import kiwi.util.*;
070
071/** This class functions as a clearinghouse for global appearance and look &
072  * feel changes for an application. <code>UIChangeManager</code> manages
073  * two lists of objects.
074  * <p>
075  * The first is a list of JFC components that need to be redrawn when the
076  * application's Look & Feel changes. Generally only top-level components,
077  * like descendants of <code>JDialog</code> and <code>JFrame</code>, need to
078  * be registered, as the <code>UIChangeManager</code> updates the Look & Feel
079  * on the entire component hierarchy of each registered component.
080  * The Kiwi <code>KFrame</code> and <code>KDialog</code>
081  * superclasses automatically register themselves with the change manager, so
082  * any class that extends either of these will inherit this behavior.
083  * <p>
084  * The second is a list of classes that wish to be notified of other, more
085  * fine-grained appearance changes that take place in the application: for
086  * example, a change in the default background texture. Potentially hundreds
087  * of components could be affected by a change in one of these appearance
088  * properties, so it would be wasteful to register all of them for
089  * notification by <code>UIChangeManager</code>. The preferred alternative is
090  * for each component to consult <code>UIChangeManager</code> for the current
091  * settings of the appropriate properties when it is constructing itself, so
092  * that its appearance is in accordance with the current settings. Obviously,
093  * only subsequently-created components will inherit appearance property
094  * changes. For this reason, interface components that employ the singleton
095  * pattern will need to register themselves as
096  * <code>PropertyChangeListener</code>s of <code>UIChangeManager</code> and
097  * redraw themselves when a property changes. <code>DialogSet</code> is an
098  * example of a class that implements this behavior.
099  *
100  * @author Mark Lindner
101  */
102
103public final class UIChangeManager implements PropertyChangeSource
104  {
105  private static UIChangeManager instance = new UIChangeManager();
106  private static Vector components, listeners;
107  private static Properties props;
108  private static PropertyChangeSupport support;
109  /** Button opacity property. */
110  public static final String BUTTON_OPACITY_PROPERTY = "button.opacity";
111  /** Default texture property. */
112  public static final String TEXTURE_PROPERTY = "texture";
113  public static final String FRAME_ICON_PROPERTY = "frame.icon";
114  private static final String DEFAULT_TEXTURE = "clouds.jpg";
115  private static final String METAL_PLAF
116    = "javax.swing.plaf.metal.MetalLookAndFeel";
117  
118  /* constructor -- singleton pattern  */
119
120  private UIChangeManager()
121    {
122    components = new Vector();
123    listeners = new Vector();
124    props = new Config();
125    support = new PropertyChangeSupport(this);
126
127    props.put(BUTTON_OPACITY_PROPERTY, Boolean.FALSE);
128    Image texture = KiwiUtils.getResourceManager().getTexture(DEFAULT_TEXTURE);
129    props.put(TEXTURE_PROPERTY, texture);
130
131    // MetalLookAndFeel.setCurrentTheme(new KiwiTheme());
132    }
133
134  /** Get a reference to the <code>UIChangeManager</code> singleton. */
135
136  public static UIChangeManager getInstance()
137    {
138    return(instance);
139    }
140
141  /** Add a <code>PropertyChangeListener</code> to this object's list of
142    * listeners. Listeners are notified whenever a property of this object
143    * is changed.
144    *
145    * @param listener The listener to add.
146    * @see #removePropertyChangeListener
147    */
148  
149  public void addPropertyChangeListener(PropertyChangeListener listener)
150    {
151    support.addPropertyChangeListener(listener);
152    }
153
154  /** Remove a <code>PropertyChangeListener</code> from this object's list of
155    * listeners.
156    *
157    * @param listener The listener to remove.
158    * @see #addPropertyChangeListener
159    */
160  
161  
162  public void removePropertyChangeListener(PropertyChangeListener listener)
163    {
164    support.removePropertyChangeListener(listener);
165    }
166  
167  /** Register a component with the manager. If the given component is already
168    * registered, the method call has no effect. The registered component will
169    * have its UI updated whenever the Look & Feel of the application changes.
170    *
171    * @param c The component to register.
172    * @see #unregisterComponent
173    */
174
175  public void registerComponent(JComponent c)
176    {
177    if(!components.contains(c))
178      components.addElement(c);
179    }
180
181  /** Unregister a component from the manager.
182    *
183    * @param c The component to unregister.
184    * @see #registerComponent
185    */
186
187  public void unregisterComponent(JComponent c)
188    {
189    components.removeElement(c);
190    }
191
192  /** Change the Look & Feel globally. Each registered component (and every
193    * child component thereof) will be updated to use the new Look & Feel.
194    *
195    * @param lf The new Look & Feel.
196    * @exception UnsupportedLookAndFeelException If the specified Look & Feel
197    * is not available.
198    */
199
200  public void changeLookAndFeel(LookAndFeel lf)
201    throws UnsupportedLookAndFeelException
202    {
203    UIManager.setLookAndFeel(lf);
204    _update();
205    }
206
207  /** Change the Look & Feel globally. Each registered component (and every
208    * child component thereof) will be updated to use the new Look & Feel.
209    *
210    * @param className The fully-qualified class name for the new Look & Feel.
211    * @exception UnsupportedLookAndFeelException If the specified Look & Feel
212    * is not available.
213    * @exception IllegalAccessException If the specified class could not be
214    * accessed.
215    * @exception InstantiationException If the specified class could not be
216    * instantiated.
217    * @exception ClassNotFoundException If the specified class could not be
218    * found.
219    */
220  
221  public void changeLookAndFeel(String className)
222    throws UnsupportedLookAndFeelException, IllegalAccessException,
223      InstantiationException, ClassNotFoundException
224    {
225    UIManager.setLookAndFeel(className);
226    _update();
227    }
228
229  /** Set the <i>transparent buttons</i> flag.
230    *
231    * @param flag The new state of the flag; if <code>true</code>,
232    * <code>KButton</code>s will be transparent by default.
233    * @see #getButtonsAreTransparent
234    * @see kiwi.ui.KButton
235    */
236
237  public static void setButtonsAreTransparent(boolean flag)
238    {
239    props.put(BUTTON_OPACITY_PROPERTY, new Boolean(!flag));
240    support.firePropertyChange(BUTTON_OPACITY_PROPERTY, null,
241                               props.get(BUTTON_OPACITY_PROPERTY));
242    }
243
244  /** Get the state of the <i>transparent buttons</i> flag.
245    *
246    * @return The current state of the flag.
247    * @see #setButtonsAreTransparent
248    * @see kiwi.ui.KButton
249    */
250
251  public static boolean getButtonsAreTransparent()
252    {
253    boolean flag = ((Boolean)props.get(BUTTON_OPACITY_PROPERTY))
254      .booleanValue();
255    return(!flag);
256    }
257  
258  /** Get the default texture used for tiling the backgrounds of
259    * <code>KPanel</code>s.
260    *
261    * @return The current texture, or <code>null</code> if there is no default
262    * texture.
263    * @see #setDefaultTexture
264    * @see kiwi.ui.KPanel
265    */
266  
267  public static Image getDefaultTexture()
268    {
269    Object o = props.get(TEXTURE_PROPERTY);
270
271    if(o == Void.class)
272      return(null);
273    else
274      return((Image)o);
275    }
276
277  /** Set the default texture used for tiling backgrounds of
278    * <code>KPanel</code>s.
279    *
280    * @param texture The new texture, or <code>null</code> if no textures
281    * should be used.
282    * @see #getDefaultTexture
283    * @see kiwi.ui.KPanel
284    */
285  
286  public static void setDefaultTexture(Image texture)
287    {
288    Object o = texture;
289    
290    props.put(TEXTURE_PROPERTY, (o == null) ? Void.class : o);
291    
292    support.firePropertyChange(TEXTURE_PROPERTY, null, o);
293    }
294
295  /**
296   * Set the default frame icon to be used for <code>KFrame</code>s.
297   *
298   * @param icon The new default frame icon, or <code>null</code> if a
299   * generic frame icon should be used.
300   *
301   * @since Kiwi 1.4.2
302   */
303
304  public static void setDefaultFrameIcon(Image icon)
305    {
306    Object o = icon;
307
308    props.put(FRAME_ICON_PROPERTY, (o == null) ? Void.class : o);
309
310    support.firePropertyChange(FRAME_ICON_PROPERTY, null, o);
311    }
312
313  /**
314   * Get the default frame icon used for <code>KFrame</code>s.
315   *
316   * @return The current frame icon, or <code>null</code> if there is no
317   * default frame icon.
318   *
319   * @since Kiwi 1.4.2
320   */
321
322  public static Image getDefaultFrameIcon()
323    {
324    Object o = props.get(FRAME_ICON_PROPERTY);
325
326    if(o == Void.class)
327      return(null);
328    else
329      return((Image)o);
330    }
331  
332  /** Set the color theme.
333   *
334   * @param theme The color theme.
335   */
336
337  public static void setColorTheme(ColorTheme theme)
338    {
339    MetalLookAndFeel.setCurrentTheme(theme);
340    try
341      {
342      UIManager.setLookAndFeel(METAL_PLAF);
343      }
344    catch(Exception ex) {}
345    }
346  
347  /* update look&feel on all components */
348
349  private void _update()
350    {
351    Enumeration e = components.elements();
352    while(e.hasMoreElements())
353      {
354      JComponent c = (JComponent)e.nextElement();
355      SwingUtilities.updateComponentTreeUI(c);
356      }
357    }
358
359  }
360
361/* end of source file */