gt: 				if ("panel" == classname) {
context: /* Thinlet GUI toolkit - www.thinlet.com
   * Copyright (C) 2002-2003 Robert Bajzat (robert.bajzat@thinlet.com)
   * 
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   * 
   * This library 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
   * Lesser General Public License for more details.
   * 
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
   * 
   */
  
  package com.bluedragon.browser.thinlet;
  
  import java.awt.AWTEvent;
  import java.awt.Color;
  import java.awt.Component;
  import java.awt.Container;
  import java.awt.Cursor;
  import java.awt.Dimension;
  import java.awt.Font;
  import java.awt.FontMetrics;
  import java.awt.Graphics;
  import java.awt.Image;
  import java.awt.MediaTracker;
  import java.awt.Rectangle;
  import java.awt.Toolkit;
  import java.awt.datatransfer.DataFlavor;
  import java.awt.datatransfer.StringSelection;
  import java.awt.event.ComponentEvent;
  import java.awt.event.FocusEvent;
  import java.awt.event.InputEvent;
  import java.awt.event.KeyEvent;
  import java.awt.event.MouseEvent;
  import java.awt.image.MemoryImageSource;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.Reader;
  import java.io.Serializable;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.Hashtable;
  import java.util.MissingResourceException;
  import java.util.ResourceBundle;
  import java.util.StringTokenizer;
  import java.util.Vector;
  
  public class Thinlet extends Container
  	implements Runnable, Serializable {
  
  	private static final long serialVersionUID = 1L;
  	private transient Font font;
  	private transient Color c_bg;
  	private transient Color c_text;
  	private transient Color c_textbg;
  	private transient Color c_border;
  	private transient Color c_disable;
  	private transient Color c_hover;
  	private transient Color c_press;
  	private transient Color c_focus;
  	private transient Color c_select;
  	private transient Color c_ctrl = null;
  	private transient int block;
  	private transient Image hgradient, vgradient;
  
  	private transient Thread timer;
  	private transient long watchdelay;
  	private transient long watch;
  	private transient String clipboard;
  	private transient ResourceBundle resourcebundle; // for internationalization
  	
  	private static ResourceBundle langResource = null; // for I18N
  	private static ResourceBundle langResourceDefault = null; // for I18N
  	private transient boolean allI18n = false; // for I18N
  	
  	// enter the starting characters of a list item text within a short time to select
  	private transient String findprefix = "";
  	private transient long findtime;
  
  	private Object content = createImpl("desktop");
  	private transient Object mouseinside;
  	private transient Object insidepart;
  	private transient Object mousepressed;
  	private transient Object pressedpart;
  	private transient int referencex, referencey;
  	private transient int mousex, mousey;
  	private transient Object focusowner;
  	private transient boolean focusinside;
  	private transient Object popupowner;
  	private transient Object tooltipowner;
  	//private transient int pressedkey;
  	
  	private static final int DRAG_ENTERED = AWTEvent.RESERVED_ID_MAX + 1;
  	private static final int DRAG_EXITED = AWTEvent.RESERVED_ID_MAX + 2;
  	
  	private static long WHEEL_MASK = 0;
  	private static int MOUSE_WHEEL = 0;
  	private static Method wheelrotation = null;
  	private static int evm = 0;
  	static {
  		try {
  			WHEEL_MASK = AWTEvent.class.getField("MOUSE_WHEEL_EVENT_MASK").getLong(null);
  			MOUSE_WHEEL = MouseEvent.class.getField("MOUSE_WHEEL").getInt(null);
  		} catch (Exception exc) { /* not 1.4 */ }
  	}
  	{
  		setFont(new Font("SansSerif", Font.PLAIN, 12));
  		//setFont((Font) getToolkit().getDesktopProperty("win.messagebox.font"));
  		setColors(0xe6e6e6, 0x000000, 0xffffff,
  			0x909090, 0xb0b0b0, 0xededed, 0xb9b9b9, 0x89899a, 0xc5c5dd);
  			
  		// disable global focus-manager for this component in 1.4
  		if (MOUSE_WHEEL != 0) {
  			try {
  				getClass().getMethod("setFocusTraversalKeysEnabled", new Class[] { Boolean.TYPE }).
  					invoke(this, new Object[] { Boolean.FALSE });
  			} catch (Exception exc) { /* never */ }
  		}
  		// set listeners flags
  		enableEvents(AWTEvent.COMPONENT_EVENT_MASK |
  			AWTEvent.FOCUS_EVENT_MASK | AWTEvent.KEY_EVENT_MASK |
  			AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | WHEEL_MASK);
  			// EVM has larger fillRect, fillOval, and drawImage(part), others are correct
  			// contributed by Ibsen Ramos-Bonilla and AK
  			try {
  				if ((System.getProperty("java.vendor").indexOf("Insignia") != -1) &&
  					System.getProperty("os.name").indexOf("Windows CE") == -1) { evm = -1; }
  			} catch (Exception exc) { /* never */ }
  	}
  
  	/**
  	 * Sets the 9 colors used for components, and repaints the whole UI
  	 *
  	 * @param background the backround of panels (dialogs, desktops),
  	 * and disabled controls, not editable texts, lines between list items
  	 * (the default value if <i>#e6e6e6</i>)
  	 * @param text for text, arrow foreground (<i>black</i> by default)
  	 * @param textbackground the background of text components, and lists
  	 * (<i>white</i> by default)
  	 * @param border for outer in inner borders of enabled components
  	 * (<i>#909090</i> by default)
  	 * @param disable for text, border, arrow color in disabled components
  	 * (<i>#b0b0b0</i> by default)
  	 * @param hover indicates that the mouse is inside a button area
  	 * (<i>#ededed</i> by default)
  	 * @param press for pressed buttons,
  	 * gradient image is calculated using the background and this press color
  	 * (<i>#b9b9b9</i> by default)
  	 * @param focus for text caret and rectagle color marking the focus owner
  	 * (<i>#89899a</i> by default)
  	 * @param select used as the background of selected text, and list items,
  	 * and in slider (<i>#c5c5dd</i> by default)
  	 */
  	public void setColors(int background, int text, int textbackground,
  			int border, int disable, int hover, int press,
  			int focus, int select) {
  		c_bg = new Color(background); c_text = new Color(text);
  		c_textbg = new Color(textbackground); c_border = new Color(border);
  		c_disable = new Color(disable); c_hover = new Color(hover);
  		c_press = new Color(press); c_focus = new Color(focus);
  		c_select = new Color(select);
  		hgradient = vgradient = null;
  		repaint();
  	}
  	
  	//setDesktopProperty+
  
  	/**
  	 * Sets the only one font used everywhere, and revalidates the whole UI.
  	 * Scrollbar width/height, spinbox, and combobox button width,
  	 * and slider size is the same as the font height
  	 *
  	 * @param font the default font is <i>SansSerif</i>, <i>plain</i>, and <i>12pt</i>
  	 */
  	public void setFont(Font font) {
  		block = getFontMetrics(font).getHeight();
  		super.setFont(font);
  		this.font = font;
  		hgradient = vgradient = null;
  		if (content != null) validate(content);
  	}
  	
  	/**
  	 *
  	 */
  	private void doLayout(Object component) {
  		String classname = getClass(component);
  		if ("combobox" == classname) {
  			if (getBoolean(component, "editable", true)) {
  				Image icon = getIcon(component, "icon", null);
  				layoutField(component, block, false,
  					(icon != null) ? icon.getWidth(this) : 0);
  			} // set editable -> validate (overwrite textfield repaint)
  			else {
  				int selected = getInteger(component, "selected", -1);
  				if (selected != -1) { //...
  					Object choice = getItem(component, selected);
  					set(component, "text", get(choice, "text"));
  					set(component, "icon", get(choice, "icon"));
  				}
  			}
  		}
  		else if (("textfield" == classname) || ("passwordfield" == classname)) {
  			layoutField(component, 0, ("passwordfield" == classname), 0);
  		}
  		else if ("textarea" == classname) {
  			String text = getString(component, "text", "");
  			int start = getInteger(component, "start", 0);
  			if (start > text.length()) { setInteger(component, "start", start = text.length(), 0); }
  			int end = getInteger(component, "end", 0);
  			if (end > text.length()) { setInteger(component, "end", end = text.length(), 0); }
  			
  			boolean wrap = getBoolean(component, "wrap", false);
  			char[] chars = null;
  			if (wrap) {
  				Rectangle bounds = getRectangle(component, "bounds");
  				chars = getChars(component, text, true, bounds.width - 4, bounds.height);
  				if (chars == null) { // need scrollbars
  					chars = getChars(component, text, true, bounds.width - block - 4, 0);
  				}
  			}
  			else {
  				chars = getChars(component, text, false, 0, 0);
  			}
  			
  			Font currentfont = (Font) get(component, "font");
  			FontMetrics fm = getFontMetrics((currentfont != null) ? currentfont : font);
  			int width = 0, height = 0;
  			int caretx = 0; int carety = 0;
  			for (int i = 0, j = 0; j <= chars.length; j++) {
  				if ((j == chars.length) || (chars[j] == '\n')) {
  					width = Math.max(width, fm.charsWidth(chars, i, j - i));
  					if ((end >= i) && (end <= j)) {
  						caretx = fm.charsWidth(chars, i, end - i);
  						carety = height;
  					}
  					height += fm.getHeight();
  					i = j + 1;
  				}
  			}
  			layoutScroll(component, width + 2, height - fm.getLeading() + 2, 0, 0, 0, 0,
  				getBoolean(component, "border", true), 0);
  			scrollToVisible(component, caretx, carety, 2, fm.getAscent() + fm.getDescent() + 2); //?
  		} 
  		else if ("tabbedpane" == classname) {
  			// tabbedpane (not selected) tab padding are 1, 3, 1, and 3 pt
  			Rectangle bounds = getRectangle(component, "bounds");
  			String placement = getString(component, "placement", "top");
  			boolean horizontal = ((placement == "top") || (placement == "bottom"));
  			boolean stacked = (placement == "stacked");
  	
  			// draw up tabs in row/column
  			int tabd = 0; Rectangle first = null; // x/y location of tab left/top
  			int tabsize = 0; // max height/width of tabs
  			for (Object tab = get(component, ":comp"); tab != null; tab = get(tab, ":next")) {
  				if ((tabd == 0) && ((first = getRectangle(tab, "bounds")) != null)) {
  					tabd = horizontal ? first.x : first.y; // restore previous offset
  				}
  				Dimension d = getSize(tab, stacked ? 8 : horizontal ? 12 : 9,
  					stacked ? 3 : horizontal ? 5 : 8);
  				setRectangle(tab, "bounds", horizontal ? tabd : 0, horizontal ? 0 : tabd,
  					stacked ? bounds.width : d.width, d.height);
  				if (stacked) {
  					tabd += d.height;
  				} else {
  					tabd += (horizontal ? d.width : d.height) - 3;
  					tabsize = Math.max(tabsize, horizontal ? d.height : d.width);
  				}
  			}
  			
  			// match tab height/width, set tab content size
  			int cx = (placement == "left") ? (tabsize + 1) : 2;
  			int cy = (placement == "top") ? (tabsize + 1) : 2;
  			int cwidth = bounds.width - ((horizontal || stacked) ? 4 : (tabsize + 3));
  			int cheight = bounds.height - (stacked ? (tabd + 3) :
  				(horizontal ? (tabsize + 3) : 4));
  			for (Object tab = get(component, ":comp"); tab != null; tab = get(tab, ":next")) {
  				Rectangle r = getRectangle(tab, "bounds");
  				if (!stacked) {
  					if (horizontal) {
  						if (placement == "bottom") { r.y = bounds.height - tabsize; }
  						r.height = tabsize;
  					}
  					else {
  						if (placement == "right") { r.x = bounds.width - tabsize; }
  						r.width = tabsize;
  					}
  				}
  				
  				Object comp = get(tab, ":comp"); // relative to the tab location
  				if ((comp != null) && getBoolean(comp, "visible", true)) {
  					setRectangle(comp, "bounds",
  						cx - r.x, stacked ? (r.height + 1) : (cy - r.y), cwidth, cheight);
  					doLayout(comp);
  				}
  			}
  			checkOffset(component);
  		}
  		else if (("panel" == classname) || (classname == "dialog")) {
  			int gap = getInteger(component, "gap", 0);
  			int[][] grid = getGrid(component);
  			int top = 0; int left = 0;
  			int contentwidth = 0; int contentheight = 0;
  			if (grid != null) { // has subcomponents
  				top = getInteger(component, "top", 0);
  				left = getInteger(component, "left", 0);
  				int bottom = getInteger(component, "bottom", 0);
  				int right = getInteger(component, "right", 0);
  				// sums the preferred size of cell widths and heights, gaps
  				contentwidth = left + getSum(grid[0], 0, grid[0].length, gap, false) + right;
  				contentheight = top + getSum(grid[1], 0, grid[1].length, gap, false) + bottom;
  			}
  			
  			int titleheight = getSize(component, 0, 0).height; // title text and icon
  			setInteger(component, ":titleheight", titleheight, 0);
  			boolean scrollable = getBoolean(component, "scrollable", false);
  			boolean border = ("panel" == classname) && getBoolean(component, "border", false);
  			int iborder = (border ? 1 : 0);
  			if (scrollable) { // set scrollpane areas
  