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: KPanel.java,v $
023   Revision 1.8  2004/05/31 07:26:36  markl
024   rewrite of focus order methods
025
026   Revision 1.7  2004/05/12 19:02:38  markl
027   comment block updates
028
029   Revision 1.6  2003/01/19 09:50:53  markl
030   Javadoc & comment header updates.
031
032   Revision 1.5  2001/03/12 09:27:56  markl
033   Source code and Javadoc cleanup.
034
035   Revision 1.4  1999/04/26 09:27:15  markl
036   Added support for solid backgrounds.
037
038   Revision 1.3  1999/04/25 04:12:41  markl
039   Changes to support solid backgrounds in addition to textures.
040
041   Revision 1.2  1999/01/10 02:25:57  markl
042   added GPL header & RCS tag
043   ----------------------------------------------------------------------------
044*/
045
046package kiwi.ui;
047
048import java.awt.*;
049import javax.swing.*;
050
051/** An extension of <code>JPanel</code> that provides some additional
052  * functionality including support for background texture tiling and
053  * named-component lookup. Lightweight components nested within the
054  * <code>KPanel</code> should be transparent and unbuffered; the tiled
055  * background will not show through heavyweight components.
056  * <p>
057  * Note that images with transparent portions should <i>not</i> be used with
058  * <code>KPanel</code>s.
059  * <p>
060  * A <code>KPanel</code> will always be transparent if a background
061  * texture has not been specified. Therefore <code>KPanel</code>s may be
062  * safely nested if only the outermost instance has a texture applied. It is
063  * recommended that <code>KPanel</code>s always be used in place of Swing
064  * <code>JPanel</code>s.
065  * <p>
066  * In most cases it is convenient to use a <code>KFrame</code> to provide a
067  * textured background for an entire window.
068  * <p>
069  * If a solid color background is desired in place of a texture, then the
070  * outermost <code>KPanel</code> should be made opaque via the call
071  * <code>setOpaque(true)</code>, and the texture should be turned off via a
072  * call to <code>setTexture(null)</code>. The background color can be set
073  * using <code>setBackground()</code> as usual.
074  *
075  * @see kiwi.ui.KFrame
076  * 
077  * @author Mark Lindner
078  */
079
080public class KPanel extends JPanel
081  {
082  private Image image = null;
083
084  /** Construct a new <code>KPanel</code>. The newly created
085    * <code>KPanel</code> will be transparent.
086    */
087
088  public KPanel()
089    {
090    super(false);
091    super.setOpaque(false);
092    }
093
094  /** Construct a new <code>KPanel</code>. Creates a new
095    * <code>KPanel</code> with the specified layout manager. The newly
096    * created <code>KPanel</code> will be transparent.
097    *
098    * @param lm The layout manager to use for the panel.
099    */
100
101  public KPanel(LayoutManager lm)
102    {
103    super(lm, false);
104    super.setOpaque(false);
105    }
106
107  /** Construct a new <code>KPanel</code>. Creates a new
108    * <code>KPanel</code> with the specified layout manager and
109    * background image.
110    *
111    * @param lm The layout manager to use for the panel.
112    * @param image The image with which the background of the panel will be
113    * tiled.
114    */
115
116  public KPanel(LayoutManager lm, Image image)
117    {
118    super(lm, false);
119
120    this.image = image;
121    super.setOpaque(false);
122    }
123
124  /** Construct a new <code>KPanel</code>. Creates a new
125    * <code>KPanel</code> with a <code>BorderLayout</code> and the
126    * specified background image.
127    *
128    * @param image The image with which the background of the panel will be
129    * tiled.
130    */
131
132  public KPanel(Image image)
133    {
134    super(new BorderLayout(0, 0), true);
135
136    this.image = image;
137    super.setOpaque(false);
138    }
139
140  /** Paint the component. Tiles the component with the background image,
141    * if one has been provided.
142    */
143
144  public void paintComponent(Graphics gc)
145    {
146    if(image == null)
147      {
148      super.paintComponent(gc);
149      }
150    else
151      {
152      Dimension size = new Dimension();
153      getSize(size);
154      int ih = image.getHeight(null);
155      int iw = image.getWidth(null);
156
157      int vc = (size.height / ih) + 1;
158      int hc = (size.width / iw) + 1;
159
160      for(int y = 0; y < vc; y++)
161        for(int x = 0; x < hc; x++)
162          gc.drawImage(image, x * iw, y * ih, null);
163      }
164    }
165
166  /** Set the background texture.
167    *
168    * @param image The image to use as the background texture for the panel.
169    */
170
171  public void setTexture(Image image)
172    {
173    this.image = image;
174    repaint();
175    }
176
177  /** Search for a component by name. Components can be named using the
178    * <code>setName()</code> method of <code>Component</code>. This is a useful
179    * way of identifying a component when comparison by reference is not
180    * possible. This method searches this <code>KPanel</code>'s component
181    * hierarchy for a component with the given name.
182    *
183    * @param name The name of the component to search for.
184    * @return The matching component, or <code>null</code> if there is no
185    * component in the component hierarchy with the given name.
186    * @see java.awt.Component#setName
187    * @see java.awt.Component#getName
188    */
189    
190  public Component getComponentByName(String name)
191    {
192    return(findComponent(this, name));
193    }
194
195  /*
196   */
197  
198  private Component findComponent(Container cont, String name)
199    {
200    int ct = cont.getComponentCount();
201
202    for(int i = 0; i < ct; i++)
203      {
204      Component subc = cont.getComponent(i);
205      if(subc.getName().equals(name))
206        return(subc);
207      }
208
209    // none of them matched, so recurse
210
211    for(int i = 0; i < ct; i++)
212      {
213      Component c = cont.getComponent(i);
214
215      if(c instanceof Container)
216        {
217        Component subc = findComponent((Container)c, name);
218        if(subc != null)
219          return(subc);
220        }
221      }
222    
223    return(null);
224    }
225
226  /** Set the focus order for this component. The focus order specifies the
227   * order in which child components will receive focus when the user presses
228   * the tab key to move between input components. 
229   *
230   * @param order The component array representing the desired focus order.
231   */
232  
233  public void setFocusOrder(JComponent order[])
234    {
235    setFocusCycleRoot(true);
236    setFocusTraversalPolicy(new KFocusTraversalPolicy(order));
237    }
238
239  /*
240   */
241
242  private class KFocusTraversalPolicy extends FocusTraversalPolicy
243    {
244    private JComponent order[];
245
246    /*
247     */
248    
249    KFocusTraversalPolicy(JComponent order[])
250      {
251      this.order = order;
252      }
253
254    /*
255     */
256    
257    public Component getComponentAfter(Container focusCycleRoot,
258                                       Component component)
259      {
260      int i = 0;
261      
262      for(; i < order.length; i++)
263        {
264        if((Component)order[i] == component)
265          break;
266        }
267
268      if(i >= order.length - 1)
269        return(null);
270      else
271        return((Component)order[++i]);
272      }
273
274    /*
275     */
276
277    public Component getComponentBefore(Container focusCycleRoot,
278                                        Component component)
279      {
280      int i = 0;
281      
282      for(; i < order.length; i++)
283        {
284        if((Component)order[i] == component)
285          break;
286        }
287
288      if((i >= order.length - 1) || (i == 0))
289        return(null);
290      else
291        return((Component)order[--i]);
292      }
293
294    /*
295     */
296    
297    public Component getFirstComponent(Container focusCycleRoot)
298      {
299      if(order.length == 0)
300        return(null);
301      else
302        return((Component)order[0]);
303      }
304
305    /*
306     */
307    
308    public Component getLastComponent(Container focusCycleRoot)
309      {
310      if(order.length == 0)
311        return(null);
312      else
313        return((Component)order[order.length - 1]);
314      }
315
316    /*
317     */
318    
319    public Component getDefaultComponent(Container focusCycleRoot)
320      {
321      return(getFirstComponent(focusCycleRoot));
322      }    
323    }  
324
325  }
326
327/* end of source file */