Webber: A Website Construction Application
HtmlPage.java
// HTML text viewer component
package library.html;
import java.awt.*;
import java.net.*;
import java.util.*;
import java.awt.event.*;
import java.awt.image.*;
import library.*; // Import library classes
// HTML Page Display
public class HtmlPage extends Canvas implements KeyListener {
// General internal variables
char[] text; // The HTML text
HtmlReader reader; // HTML text reader object
private DrawStringBuffer lineBuffer; // Buffer for Graphics.drawString
private boolean hidden, update, spaced; // Internal state flags
private Point centre; // Point used for line-centre
private int newLines; // Newlines counter
// Font settings
private String fontName; // Internal font name
private int fontSize; // Internal font size
private boolean bold, italic, underline; // Internal font settings
private boolean validFont; // Update-system-font flag
// Font metrics
private FontMetrics fm; // Current metrics object
private int ascent, descent; // Font height
int tabsize; // Width of a TAB character
// Page settings
private int borderX = 10, borderY = 14; // Text borders
private int indentLeft, indentRight; // Text indentation
private int xpos, ypos; // Output cursor location
private int lineTop; // Current top of line
private boolean isPre; // Pre-formatted mode flag
private boolean isPlain; // Plain-text format flag
int left, top; // Window view offsets
int listDepth; // Current list depth
// Page metrics
private Dimension htmlSize; // Total HTML width/height
private int linewidth, pageright, pageheight; // Window-relative metrics
private int vAdvance; // Vertical advance height
private int alignStart; // Alignment start position
int lineheight; // Normal font height
// Return the HtmlReader being used to read tag objects
public HtmlReader getHtmlReader() { return reader; }
// Return a fully resolved URL or String reference for the specified filename
// Overridden by objects which provide file I/O for the HtmlPage (eg HtmlFile)
public Object getHref(String name) { return name; }
// Open a URL and replace the current text (overridden as above)
public boolean openUrl(String addr) { return false; }
// Return normal text color settings
protected Color getNormalColor() { return Color.black; }
protected Color getLinkColor() { return Color.blue; }
// Invalidate the current font settings for a call to updateFont()
private void newFont() { validFont = false; }
// Set current font settings from Font
public synchronized void setFont(Font f) {
fontName = f.getName();
fontSize = f.getSize();
bold = f.isBold();
italic = f.isItalic();
newFont();
}
// Default font settings (override to change defaults)
protected Font getNormalFont() { return new Font("Serif", Font.PLAIN, 16); }
protected Font getTeleFont() { return new Font("Monospaced", Font.PLAIN, 14); }
// Select default fonts
protected void setNormalFont() { setFont(getNormalFont()); }
protected void setTeleFont() { setFont(getTeleFont()); }
// Return the current font for this state
public Font getFont() {
if (fontName==null) return getNormalFont(); // Initialization font
int style = (bold?Font.BOLD:0) | (italic?Font.ITALIC:0);
return new Font(fontName, style, fontSize); // Active font
}
// Set the vertical advance height
private void setVerticalAdvance(int h) { if (h > vAdvance) vAdvance = h; }
// Read and set current font metrics
private void setFontMetrics(Graphics g) {
fm = g.getFontMetrics(); // Get metrics object
ascent = fm.getMaxAscent(); // Get font ascent
descent = fm.getMaxDescent(); // Get font descent
tabsize = fm.stringWidth("_") * 8; // Calculate tab width
setVerticalAdvance(getLineHeight()); // Update max line height
}
// Set current font and update metrics (if necessary)
private void updateFont(Graphics g) {
if (!validFont) { // Not already set?
g.setFont(getFont()); // Set Graphics font
setFontMetrics(g); // Get font metrics
validFont = true; // Validate font
}
}
// Change individual settings for the current font
protected void setFontName(String name) { fontName = name; newFont(); }
protected void setFontSize(int size) { fontSize = size; newFont(); }
protected void setBold(boolean state) { bold = state; newFont(); }
protected void setItalic(boolean state) { italic = state; newFont(); }
protected void setUnderline(boolean state) { underline = state; }
// Restore individual font settings to normal
protected void setFontName() { setFontName(getNormalFont().getName()); }
protected void setFontSize() { setFontSize(getNormalFont().getSize()); }
// Initialize font settings
private void initFont() { setUnderline(false); setNormalFont(); }
// Initialize page state for drawing
private void initPage() {
listDepth = 0; // Initialize list depth
indentLeft = indentRight = 0; // Reset indentation
spaced = false; // Reset spacing-flag
newLines = 2; // Reset newline counter
xpos = borderX; // Initial x-coordinate
ypos = borderY; // Initial y-coordinate
lineTop = ypos; // Store top of line
vAdvance = 0; // Reset maximum line height
alignStart = borderX; // Reset alignment start pos
}
// Read and set current page metrics
private void setPageMetrics() {
Dimension d = getSize();
linewidth = d.width - borderX*2 - indentLeft - indentRight;
pageright = d.width - borderX - indentRight;
pageheight = d.height;
}
// Set the page to the home (top-left) position
private void home() { left = top = 0; }
// Returns true if the current line is visible
private boolean isLineVisible() { return (!hidden) && ((ypos+ascent)>=top); }
// Returns true if position x is past the right of this page
private boolean isPageRight(int x) { return (x >= pageright); }
// Returns true the current position is past the bottom of this page
private boolean isPageBottom() { return (ypos >= top+pageheight); }
// Returns true if currently at the start of an empty line
private boolean isNewLine() { return (newLines > 0); }
// Return the current height of a line of text
private int getLineHeight() { return ascent + descent; }
// Return the page starting position
int getPageStart() { return borderY; }
// Return the line starting position
int getLineStart() { return borderX + indentLeft; }
// Return the number of normal-height lines which would fit on this page
int getNumLines() { return pageheight / lineheight; }
// Add a height offset to the total HTML height (used by HtmlEdit)
void addHtmlHeight(int height) { htmlSize.height += height; }
// Set new text for this page
private void resetText(char[] text) {
this.text = text; // Set new text object
if (isPlain) reader.setPlainText(text); // Plain text or HTML?
else reader.setText(text); // Build a new tag list
update = true; // New metrics (via paint)
}
// Update the text after adding offset chars at pos (partial tag-list rebuild)
protected void updateText(char[] text, int pos, int offset) {
this.text = text; // Set new text object
if (isPlain) reader.setPlainText(text); // Plain text or HTML?
else reader.updateText(text, pos, offset); // Update the tag list
}
// Initialize page offsets and settings and update text
public void setText(char[] text, boolean isPlain) {
home(); this.isPlain = isPlain; resetText(text);
}
// Return the HTML text
public char[] getText() { return text; }
// Returns true if text should be displayed in pre-formatted mode
public boolean isPlainText() { return false; }
// Set the text-formatting mode for this page (normal or preformatted)
public void setPreformat(boolean state) { isPre = state; }
// Enable/disable line-centre (enable from the current location)
public void setCentre(boolean state) {
centre = (state==false) ? null : new Point(borderX, ypos);
}
// Fill an area with the component's background colour
private void clearArea(int x, int y, int w, int h, Graphics g) {
Lib.fillArea(x, y, w, h, getBackground(), g);
}
// Offset any click areas on the line currently being centred
private void centreClickAreas(int offset) {
Enumeration e = clickAreas.elements(); // Get ClickArea list
boolean moveArea = false; // True if target line
ClickArea a;
while (e.hasMoreElements()) { // End of list?
a = (ClickArea) e.nextElement(); // Get next area
if (!moveArea) // At target line?
if (a.start.y >= centre.y) moveArea = true;
if (moveArea) { // Move this area?
a.start.x += offset; // Offset start pos
a.end.x += offset; // Offset end pos
}
}
}
// Centre the line just drawn
private void centreline(Graphics g) {
if (centre==null) return; // Centre not active?
int w = xpos-centre.x; // Get text width
if (w < 1) return; // Empty line?
int h = ypos-centre.y, offset = (linewidth - w) / 2;
g.copyArea(centre.x, centre.y, w, h, offset, 0);// Translate text
clearArea(centre.x, centre.y, offset, h, g); // Crop copied area
centreClickAreas(offset); // Adjust click areas
}
// Align text preceding an image and set alignment for following text
private void alignText(Rectangle r, int align, Graphics g) {
setVerticalAdvance(r.height); // Set line height
if (align==2) return; // Align top
int offset = (align==1) ? r.height / 2 // Align middle
: r.height; // Align bottom
if ((offset -= ascent) < 0) return; // Trap negative offset
int w = xpos - alignStart, h = getLineHeight(); // Get text dimensions
g.copyArea(alignStart, ypos, w, h, 0, offset); // Move text
clearArea(alignStart, ypos, w, (h < offset) ? h : offset, g);
ypos += offset; // Add line offset
}
// Attempt to start loading and drawing an image (wait for width & height)
private boolean startImage(Image i, int x, int y, Graphics g) {
if (g.drawImage(i, x, y, this)) return true; // Image is ready?
int f, size = ImageObserver.WIDTH | ImageObserver.HEIGHT,
quit = ImageObserver.ERROR | ImageObserver.ABORT;
while (((f = checkImage(i, this)) & size) != size)
if ((f & quit) != 0) return false; // Load failed
return true; // Load started
}
// Create and return a click area for image or null if no click area is active
private ClickArea startImageClickArea(int w, int h, Graphics g) {
ClickArea a = getClickArea(); // Get active area
if (a==null) return null; // No active area?
endClickArea(); // End text area
addClickArea(a.listener); // Add image area
a = getClickArea(); // Get image area
endClickArea(a.start.x + w, a.start.y + h, g); // End image area
return a; // Return new area
}
// Draw an image at the current location
private LinkList images = new LinkList();
public void drawImage(Image i, Graphics g) { drawImage(i, 0, g); }
public void drawImage(Image i, int align, Graphics g) {
if (isPre) return; // No images if pre-formatted (to be continued)
if (ypos!=lineTop) ypos = lineTop; // Restore top of line
if (!startImage(i, xpos, ypos, g)) return; // Attempt image load
int w = i.getWidth(this), h = i.getHeight(this);// Get image size
ClickArea a = startImageClickArea(w, h, g); // Modify click area
Rectangle r = new Rectangle(xpos, ypos, w, h); // Create image locator
images.addElement(r); // Store image location
alignText(r, align, g); // Align adjacent text
xpos += w; // Advance position
alignStart = xpos; // Set align start pos
newLines = 0; // Reset newline count
if (a!=null) addClickArea(a.listener); // Restart click area
}
// Override Component to draw complete images only
public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h) {
if ((flags & (FRAMEBITS|ALLBITS)) != 0) // Complete image?
repaint(); // Repaint component
return (flags & (ALLBITS|ABORT)) == 0; // False if complete
}
// Move xpos to skip over any images between xpos and xpos+w
private void skipImages(int w) {
boolean skipped = false; // Reset skipped flag
Enumeration e = images.elements(); // Get active images
while (e.hasMoreElements()) { // Check images for x
Rectangle r = (Rectangle)e.nextElement();
if ((xpos < r.x + r.width) && (xpos + w > r.x)) {
xpos = r.x + r.width; // Skip over the image
skipped = true; // Set skipped flag
} else if (skipped) break; // Clear after skipping?
}
if (skipped) alignStart = xpos; // Set align start pos
}
// Remove all images cleared by the current line (ypos)
private void clearImages() {
Enumeration e = images.elements(); // Get active images
while (e.hasMoreElements()) { // Remove cleared images
Rectangle r = (Rectangle)e.nextElement();
if (ypos >= r.y + r.height) images.removeElement(r);
}
}
// Centre line (if required) and move to the start of the next line
// Also breaks and continues the area monitored by a ClickListener (if any)
private void endline(boolean hidden, Graphics g) {
ClickArea a = getClickArea(); // Get active click area
if (a!=null) { // Click area is active?
a.isMulti = true; // Set multi-line flag
endClickArea(); // Terminate click area
}
updateFont(g); // Validate current font
newLines++; // Inc. newline count
// ypos += getLineHeight(); // Move to the next line
// ypos += vAdvance; // Advance past line
ypos = lineTop + vAdvance; // Advance past line
lineTop = ypos; // Store top of line
vAdvance = getLineHeight(); // Reset vertical advance
if (!hidden) centreline(g); // Centre visible line?
else if (xpos>htmlSize.width) htmlSize.width = xpos; // Get metrics
xpos = getLineStart(); // Move to start of line
alignStart = borderX; // Reset align start pos
if (centre!=null) setCentre(true); // Reset line-centre
clearImages(); // Remove cleared images
if (a!=null) addClickArea(a.listener); // Continue click area?
}
// Move current position to the start of the next line
public boolean nextline(Graphics g) {
lineBuffer.flush();
endline(hidden, g);
return hidden ? true : !isPageBottom();
}
// Move current position to the next line only if necessary
public boolean newline(Graphics g) {
return (isNewLine()) ? true : nextline(g);
}
// Move current position to the start of the next paragraph
public boolean newpara(Graphics g) {
for (int i=newLines; i<2; ++i)
if (!nextline(g)) return false;
return true;
}
// Add values to the left & right indents
private void addIndent(int left, int right) {
lineBuffer.flush();
indentLeft += left;
indentRight += right;
xpos = getLineStart();
setPageMetrics(); // Update page metrics
}
public void addIndent(int indent) { addIndent(indent, 0); }
public void addIndents(int indent) { addIndent(indent, indent); }
// Write a word or a space and update the current position (with underlining)
private boolean drawWord(String word, Graphics g) {
int w = fm.stringWidth(word); // Get word width
skipImages(w); // Skip over any images
if (isPageRight(xpos+w)) // Past end of line?
if (w<=linewidth) { // Fit on next line?
if (!nextline(g)) return false; // Move to next line
else if (word.charAt(0)==' ') return true;
} else if (!isNewLine()) // Next line is longer?
if (!nextline(g)) return false; // Move to next line
if (isLineVisible()) { // Visible line?
int y = ypos+ascent; // Get text baseline
// g.drawString(word, xpos, y); // Non-buffer drawing
lineBuffer.drawString(word, xpos, y, g);// Draw via buffer
if (underline) g.drawLine(xpos, y+2, xpos+w-1, y+2);
}
xpos += w; // Advance current xpos
newLines = 0; // Reset newline count
return true;
}
// Return the character represented by a character-conversion code
private static final String[] // Code strings
codeString = { "lt", "gt", "amp", "quot", "nbsp", "reg", "copy" };
private static final char[] // Code characters
codeChar = { '<', '>', '&', '"', ' ', '\u00AE', '\u00A9'};
private static char getCodeChar(String code) {
if (code==null) return 0; // No code string?
if (code.length()==0) return 0; // Empty code string?
if (code.charAt(0)=='#') // Character value?
return (char)Integer.valueOf(code.substring(1)).intValue();
for (int i=0; i < codeString.length; ++i) // Search code array
if (code.equals(codeString[i])) // Compare codes
return codeChar[i]; // Return character
return 0; // Code not found
}
// Perform character conversions before drawing text
private static String parseText(String s) {
StringBuffer buf = new StringBuffer(s.length());// Get a string buffer
boolean isCoded = false; // Reset conversion flag
String code;
char c, ch;
for (int i=0, num=s.length(); i < num; ++i) { // Check each character
if ((ch = s.charAt(i))=='&') { // Conversion character?
code = Lib.getDelimitedString(s, i, '&', ';');
if ((c = getCodeChar(code))!=0) {
ch = c; // Convert character
i += code.length() + 1; // Skip code & semi
isCoded = true; // Set conversion flag
}
}
buf.append(ch); // Add char to buffer
}
return isCoded ? buf.toString() : s; // Converted or original
}
// Draw a either a word or (for whitespace characters) a space
private boolean putText(String s, String delim, Graphics g) {
if (delim.indexOf(s.charAt(0)) >= 0) // Whitespace?
if (isNewLine()) return true; // Start of line?
else if (spaced) return true; // Already spaced?
else { s = " "; spaced = true; } // Translate to space
else { // Non-whitespace (text)
spaced = false; // Indicate no spaces
s = parseText(s); // Convert characters
}
return drawWord(s, g); // Output on display
}
// Draw a line of pre-formatted text (with tabs) and return new xpos
// Output is prevented if g is null to allow text to be measured
int textLine(String s, int x, int y, Graphics g) {
String delim = "\t";
StringTokenizer st = new StringTokenizer(s, delim, true);
int inset = getLineStart();
y += ascent;
while (st.hasMoreTokens()) {
s = st.nextToken();
if (delim.indexOf(s.charAt(0))>=0) { // Tabs?
for (int i=s.length(); i>0; --i)
x += -((x-inset) % tabsize) + tabsize;
} else { // Text & spaces
int w = fm.stringWidth(s); // Get total width
if (g!=null) { // Display? (not just measuring)
g.drawString(s, x, y);
if (underline) g.drawLine(x, y+2, x+w-1, y+2);
}
x += w; // Increment position
}
}
return x;
}
// Draw (or measure if not visible) a line of pre-formatted text (with tabs)
private void putLine(String s, Graphics g) {
xpos = textLine(s, xpos, ypos, isLineVisible() ? g : null);
}
// Execute a newline for every '\n' character in s
private boolean putNewLines(String s, Graphics g) {
for (int i=s.length(); i>0; --i)
if (s.charAt(i-1)=='\n')
if (!nextline(g)) return false;
return true;
}
// Helper classes used to extend the functionality of drawText
class TextWriter { // Writes text in HTML format
String getDelimiters() { return "\r\n \t"; }
StringTokenizer getTokenizer(String s) {// Get an appropriate tokenizer
return new StringTokenizer(s, getDelimiters(), true);
}
boolean write(String s, Graphics g) { // Write a word or a space
return putText(s, getDelimiters(), g);
}
}
class PreTextWriter extends TextWriter { // Writes pre-formatted text
String getDelimiters() { return "\r\n"; }
boolean write(String s, Graphics g) { // Write text line or newlines
if (getDelimiters().indexOf(s.charAt(0)) < 0) putLine(s, g);
else if (!putNewLines(s, g)) return false;
return true;
}
}
// Draw text on page in normal or pre-formatted mode
public boolean drawText(String s, Graphics g) {
TextWriter w; // Text writer helper-object
if (!isPre) w = new TextWriter(); // HTML-format text
else w = new PreTextWriter(); // Pre-formatted text
boolean done = true; // Set end-of-page flag
updateFont(g); // Set font if required
StringTokenizer st = w.getTokenizer(s); // Get text tokenizer
while (st.hasMoreTokens()) {
s = st.nextToken(); // Get & draw next line/word
if (!w.write(s, g)) { done = false; break; }
}
lineBuffer.flush(); // Draw remaining text
return done;
}
// Draw all tag-objects on this page (visible or hidden)
private void drawPage(boolean hidden, Graphics g) {
initPage(); // Initialize page state
setPageMetrics(); // Initialize page settings
initFont(); // Initialize font settings
if (isPlain) setPreformat(true); // Plain text mode
else setPreformat(isPlainText()); // Set text-formatting mode
updateFont(g); // Apply initial font settings
setCentre(false); // Initialize centre-line state
this.hidden = hidden; // Set visibility mode
clickAreas.removeAllElements(); // Initialize click area list
reader.drawText(this, g); // Draw tags using HtmlReader
endClickArea(); // Terminate click area (if any)
}
// Recalculate global page metrics (lineheight & htmlSize)
private void updatePage(Graphics g) {
htmlSize = new Dimension(); // Initialize HTML dimensions
initFont(); // Initialize default font
updateFont(g); // Set Graphics font
lineheight = getLineHeight(); // Get normal line height
drawPage(true, g); // Draw page in hidden mode
htmlSize.height = ypos; // Set total page height
update = false; // Reset update flag
}
// Repaint this page - recalculates lineheight and htmlSize if updated
public void paint(Graphics g) {
if (update) updatePage(g); // First call since update?
GraphicsBuffer buf = new GraphicsBuffer(); // Get a double-buffer
Dimension d = getSize(); // Modify buffer width
if (htmlSize.width > 0) d.width = htmlSize.width;
Rectangle r = new Rectangle(0, 0, d.width, d.height);
g = buf.getGraphics(this, r, g); // Get hidden Graphics context
g.translate(0, -top); // Translate vertical view
drawPage(false, g); // Draw page in visible mode
buf.paint(-left, 0); // Translate image to display
buf.crop(-left, 0); // Crop to the image edges
// requestFocus(); // For keyboard input (no need?)
}
// Override Component to skip clearing the component (due to GraphicsBuffer)
public void update(Graphics g) { g.setColor(getForeground()); paint(g); }
// Process keys
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP: // Up arrow
if (top<=0) return;
if ((top -= lineheight)<0) top = 0;
break;
case KeyEvent.VK_DOWN: // Down arrow
if (top+pageheight+lineheight>=htmlSize.height+borderY) return;
top += lineheight;
break;
case KeyEvent.VK_LEFT: // Left arrow
if (left<=0) return;
if ((left -= tabsize)<0) left = 0;
break;
case KeyEvent.VK_RIGHT: // Right arrow
left += tabsize;
break;
case KeyEvent.VK_PAGE_UP: // Page Up
if (top<=0) return;
top -= getNumLines() * lineheight;
if (top < 0) top = 0;
break;
case KeyEvent.VK_PAGE_DOWN: // Page Down
int l = getNumLines() * lineheight;
if (top+l >= htmlSize.height+borderY) return;
top += l;
break;
case KeyEvent.VK_HOME: // Home
if (top<=0) return;
top = 0;
break;
case KeyEvent.VK_END: // End
top = htmlSize.height+borderY - (getNumLines() * lineheight);
break;
default: return; // Unrecognized
}
repaint();
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public boolean isFocusTraversable() { return true; }
// Interface used by HtmlPage to access a ClickListener tag
public interface ClickListener { public void mouseClicked(HtmlPage p); }
// Click area information class stored in the clickAreas list
class ClickArea {
ClickListener listener; // Object listening for clicks in this area
Point start, end; // Area covered by this ClickListener
boolean isMulti; // True if this is a multi-line click area
ClickArea(ClickListener l, int x, int y) { // Constructor
listener = l; // Set click listener
start = new Point(x, y); // Set starting point
end = null; // Initialize end point
isMulti = false; // Initialize multiline
}
}
// A list of ClickArea objects for tags interested in mouse clicks (eg. links)
private LinkList clickAreas = new LinkList(); // ClickArea objects
// Return the currently active click area, or null if none
private ClickArea getClickArea() {
int size = clickAreas.size();
if (size==0) return null;
ClickArea a = (ClickArea) clickAreas.elementAt(size-1);
return (a.end==null) ? a : null;
}
// Add a ClickArea to the list and store it's starting location
protected void addClickArea(ClickListener l) {
if (hidden) return; // Ignore if hidden
if (getClickArea()!=null) return; // Already active?
ClickArea a = new ClickArea(l, xpos, ypos); // Create a click area
clickAreas.addElement(a); // Add to area list
}
// Store the ending location of a ClickArea (or remove it if invisible)
protected boolean endClickArea() { // Text area
return endClickArea(xpos, ypos + getLineHeight(), null);
}
private boolean endClickArea(int xpos, int ypos, Graphics g) {
ClickArea a = getClickArea(); // Get active area
if (a==null) return false; // No active area?
if (!isLineVisible() || (a.start.x==xpos)) { // Invisible area?
clickAreas.removeElement(a); // Remove listener
return true; // Abort
}
a.end = new Point(xpos, ypos); // Set ending point
if (g!=null) { // Draw area outline?
Color c = g.getColor(); // Save current colour
g.setColor(getLinkColor()); // Set link colour
Point s = a.start, e = a.end; // Draw a rectangle
g.drawRect(s.x, s.y, e.x-s.x-1, e.y-s.y-1);
g.setColor(c); // Restore colour
}
return true;
}
// Activate a ClickLister tag if it applies to the location of a mouse event
private void checkClick(ClickArea a, MouseEvent m) {
Point s = a.start, e = a.end; // Get area location
int x = m.getX() + left, y = m.getY() + top; // Get click location
if ((x < s.x) || (x >= e.x)) return; // Horizontal check
if ((y < s.y) || (y >= e.y)) return; // Vertical check
a.listener.mouseClicked(this); // Call ClickListener
}
// Page constructors
public HtmlPage(char[] text) { this(text, new HtmlPageReader()); }
public HtmlPage(char[] text, HtmlReader reader) { this(text, false, reader); }
public HtmlPage(char[] text, boolean isPlain, HtmlReader reader) {
this.reader = reader; // Set HTML reader
lineBuffer = new DrawStringBuffer(); // Get drawString buffer
setText(text, isPlain); // Set text/init reader
addKeyListener(this); // Listen for keys
// Create and override a private ComponentAdapter for resize events
addComponentListener(new ComponentAdapter() {
// Metrics update required if component is resized
public void componentResized(ComponentEvent e) { update = true; }
});
// Create and override a private MouseAdapter for mouse clicks
addMouseListener(new MouseAdapter() {
// Propogate MouseEvent to all interested ClickListeners
public void mouseClicked(MouseEvent e) {
requestFocus(); // Get input focus
Enumeration a = clickAreas.elements();
while (a.hasMoreElements()) // Check clickAreas
checkClick((ClickArea)a.nextElement(), e);
}
});
}
}
Go To:
Source Code