| ScrollingBannerCustomizer.java |
netscape.samples.widgets.ScrollingBannerCustomizer.java |
* Do not be alarmed: this is intentional and should * not impact the usability of the JavaDocs as a reference. *
* This class is used as a customizer for the ScrollingBanner * JavaScript Bean. */ public class ScrollingBannerCustomizer extends Panel implements Customizer, NSCustomizer, KeyListener { ////////////////////////////////////////////////////// // // Animation related variables // private String msg; private FontMetrics fm; private int delay = 20; private int currentPos = 0; private StringBuffer out; private int totalWidth= 20; // Ubiquitious dbl buffered graphics variables. private Image buffImg = null; private Graphics buffG = null; // Default font private Font font=new Font("Helvetica",Font.PLAIN, 12); private int fontHeight = 0; // this is initialized in init private int fontWidth = 0; // this is initialized in init private Image borderImg = null; private Graphics borderG = null; // for drawing border private int xDim, yDim; ////////////////////////////////////////////////////// // // Variables used for the basic Customizer // private TextField textField; private TextField speedField; public Font textFont = new Font("TimesRoman",Font.ITALIC | Font.BOLD,26); public Color textColor = new Color(80,80,180); public Color backgroundColor = new Color(200,200,255); private Inspectable _inspectable = null; private Property[] _property = null; ////////////////////////////////////////////////////// // // Standard methods for getProperty and setProperty // useful for all NSCustomizers below: // /** * Gets the named property (from the property array) * and returns a string value for the property * * @see setProperty */ public String getProperty(String propName) { Object retVal = null; boolean valFound = false; if (_property == null ) { System.out.println("Properties array uninitialized"); return null; } for (int i=0; i<_property.length; i++) { try { if ( propName.equals(_property[i].getName() ) ){ retVal = _property[i].getValue(); valFound= true; break; } } catch (CascadedException e) { System.out.println("Exception generated while retrieving value\n"+e); } } if(!valFound) { System.out.println("An invalid Property was specified (Property not found)"); return null; } if(!(retVal instanceof String)) { System.out.println("A non-String value was returned for a Property"); return null; } return((String)(retVal)); } /** * Sets the named property (from the property array) * to the string value specified and returns a boolean * indicating success or failure. * * @see getProperty */ public boolean setProperty(String propName, String value) { boolean valFound = false; if (_property == null ) { System.out.println("Properties array uninitialized"); return false; } for (int i=0; i<_property.length; i++) { try { if ( propName.equals(_property[i].getName() ) ){ _property[i].setValue(value); valFound= true; break; } } catch (CascadedException e) { System.out.println("Exception generated while setting value\n"+e); } } if(!valFound) { System.out.println("An invalid Property was specified (Property not found)"); return false; } // The setProperty was successful return true; } /** * If a customizer implements NSCustomizer, then this * setObjectInspectable will be called instead of the the * regular setObject. This allows the customizer to have access * to both the Java Bean, as well as the tag object that * contains the bean on the page. */ public void setObjectInspectable(Object bean, Inspectable tag) throws CascadedException{ _inspectable = tag; _property = _inspectable.getProperties(); Label textLabel = new Label("Message:", Label.RIGHT); add(textLabel); textLabel.setBounds(10, 80, 60, 30); textField = new TextField(getProperty("msg"), 20); add(textField); textField.setBounds(80, 80, 400 - 80, 30); textField.addKeyListener(this); textLabel = new Label("Speed:", Label.RIGHT); add(textLabel); textLabel.setBounds(10, 130, 60, 30); speedField = new TextField(getProperty("speed"), 20); add(speedField); speedField.setBounds(80, 130, 60, 30); textLabel = new Label("(Note: To restart / reset scroller animation, move", Label.RIGHT); add(textLabel); textLabel.setBounds(10, 170, 380, 30); textLabel = new Label("mouse pointer out of / back into this window)", Label.RIGHT); add(textLabel); textLabel.setBounds(10, 200, 380, 30); } /** * If the customizer returns a Netscape IFC view it will be used * and placed into an internal window. */ public Object getCustomizerView() throws CascadedException { return this; } /** * Called whenever something interesing happens to a Observable. * @param o The Observable that changed. */ public void changed(Observable o) { support.firePropertyChange("", null, null); } ////////////////////////////////////////////////////// // // Standard methods all JSB Customizers need // public ScrollingBannerCustomizer() { setBackground(backgroundColor); setLayout(null); } public void setObject(Object obj) { // This gets called with 'null' when // the customizer is closed down, // to assist with Garbage Collection if(obj != null) { System.out.println("This customizer is for a JavaScriptBean"); System.out.println("This method should only be called if"); System.out.println("this is a customizer for a JavaBean."); } } public void update(Graphics g) { g.setFont(textFont); g.setColor(textColor); g.drawString("ScrollingBanner Customizer",20,30); paintScroller (g); } /** * Paint calls update for good dbl buffering... */ public void paint (Graphics g) { // Have paint call update for good dbl buffering... update(g); } /** * Returns the preferred size for our customizer */ public Dimension getPreferredSize() { return new Dimension(420, 255); } /** * Forces a repaint on keystrokes */ public void keyTyped(KeyEvent e) { repaint(); } /** * Forces a repaint on keypresses */ public void keyPressed(KeyEvent e) { repaint(); } /** * On a key release event, set the msg and * speed properties to match the values * of the textfields */ public void keyReleased(KeyEvent e) { String txt = textField.getText(); setProperty("msg",txt); txt = speedField.getText(); setProperty("speed",txt); } /** * Old method used only for older layout managers */ public Dimension preferredSize() { return getPreferredSize(); } ////////////////////////////////////////////////////// // // Additional Methods for supporting Adding and // Removing listeners // public void addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } private PropertyChangeSupport support = new PropertyChangeSupport(this); ////////////////////////////////////////////////////// // // Animation-related methods // /** * Creates the graphics buffers used for * the animation */ private boolean createScrollGraphics () { xDim = this.size().width-20; yDim = 26; //this.size().height; borderImg = createImage(xDim, yDim); borderG = borderImg.getGraphics(); borderG.setFont(font); fm = borderG.getFontMetrics(); fontHeight = fm.getHeight() + 2; fm = borderG.getFontMetrics(); if(borderG != null && buffG != null) return true; else return false; } /** * Called by paint, this paints the animated * scroller portion of the customizer and calls * repaint at the end with a delay based on the * speed parameter */ private void paintScroller(Graphics g) { msg = textField.getText(); String speed = speedField.getText(); if(speed != null) { try { delay = Integer.parseInt(speed); } catch (Exception e) { // in case there is an exception // while converting the integer System.out.println("Error parsing speed"); } } if (borderG == null) { if (!createScrollGraphics()) { System.out.println("Unable to create scroller"); // Try again... repaint(200); return; } } borderG.setColor(Color.lightGray); borderG.fillRect(0,0,xDim, yDim); borderG.setColor(Color.black); if (msg != null) { ////////////////////////////////////// // // The following code was ported directly // from the JavaScript Bean to attempt // to match the animation used in the // browser at run-time with the preview // this customizer provides at design-time. // // The "this." references are valid Java, // and are required in the JavaScript Bean. // They have been left in place to emphasize // the similarity between this code and the // animation code in the start method for the // ScrollingBanner. this.out = new StringBuffer(" "); // Use animation algorithm directly from JavaScript for (int i = 0; i < this.currentPos; i++) this.out.append(" "); try { if (this.currentPos >= 0) this.out.append(this.msg); else this.out = new StringBuffer(this.msg.substring(-this.currentPos, this.msg.length())); } catch (Exception e) { // in case there is an exception // while retrieving the substring System.out.println("Error creating animation"); } borderG.drawString(this.out.toString(), 0, fontHeight); this.currentPos--; if (this.currentPos < -(this.msg.length())) { this.currentPos = 0; } } // Draw cool border borderG.drawLine(1,1,xDim-1,1); borderG.drawLine(1,1,1,yDim-1); borderG.setColor(Color.gray); borderG.drawLine(0,0,xDim,0); borderG.drawLine(0,0,0,yDim); borderG.setColor(Color.lightGray); borderG.drawLine(xDim-2,1,xDim-2,yDim-2); borderG.drawLine(1,yDim-2,xDim-2,yDim-2); borderG.setColor(Color.white); borderG.drawLine(xDim-1,0,xDim-1,yDim-1); borderG.drawLine(0,yDim-1,xDim-1,yDim-1); g.drawImage(borderImg, 10, 50, this); // Create a delay based on the amount of time // remaining before the next frame. // Extra delay is to make speed seem closer to // actual speed in browser // NOTE: // This is a cheap, hacky way of getting animations. // A more sophisticated way would be to use threads... // (an exercise for the curious reader) repaint((long)(delay * 1.12)); } /** * Triggers a repaint when the mouse enters the * customizer */ public boolean mouseEnter(Event evt,int x, int y) { currentPos = 0; repaint(); return true; } }