| ScrollingBannerCustomizer.java

netscape.samples.widgets.ScrollingBannerCustomizer.java

    /**
     * Note: Images may be missing from the JavaDocs generated.<p>
     * <b>Do not be alarmed</b>: this is intentional and should
     * not impact the usability of the JavaDocs as a reference.
     * <p>
     * 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;
        }
    }