advertisement
javaboutique
Search Tips
Articles  |   Tutorials  |   Reviews  |   Tools  |   by Category  |   by Date  |   by Name  |   Submit  |   Source  |   Forums  |  
javaboutique
Browse DevX


Partners & Affiliates











advertisement

PopupNavigator


Java Source:

// PopupNavigator -  web-site navigation pop-up menu Java applet.
// Copyright © 1999-2000 Branko Dimitrijevic
// bepp@bepp.8m.com
// http://bepp.8m.com

package PopupNavigator;

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.StringTokenizer;
import java.net.URL;
import java.net.MalformedURLException;



// TODO: Support for settig predefined cursor or loading
// a cursor from URL.

// TODO: Support for foregraund color, background color,
// icons, foreground and background image.

// TODO: Merge PopupNavigatorMenu and PopupNavigatorMenuItem?

// TODO: Support for system colors.

// TODO: Support for configuration file.
//   1) For menu tree only.
//   2) For everything except menu tree.
//   3) For both 1) and 2).

// TODO: Test when there is too mutch sub-parameters.



class PopupNavigatorMenu extends Menu {

  // We don't use Font class because we need to know what values are
  // default (null) - after temporary change of font.
  public String fontName = null;
  public Integer fontStyle = null, fontSize = null;

  public PopupNavigatorMenu(String label) {
    super(label);
  }

}



// We need special class to store URLs.
class PopupNavigatorMenuItem extends MenuItem {

  public URL url = null;
  // Stores URLs that are in the different domain (to avoid premature DNS lookups).
  public String url_string = null;
  public String frame = null;

  // We don't use Font class becouse we need to know what values are
  // default (null) - after temporary change of font.
  public String fontName = null;
  public Integer fontStyle = null, fontSize = null;

  public PopupNavigatorMenuItem(String label) {
    super(label);
  }

} // PopupNavigatorMenuItem



public class PopupNavigatorApplet extends Applet {

  // True if mouse is inside applet.
  private boolean mouseIn = false;
  private boolean mouseDown = false;

  // Maximum number of semicolon-delimited tokens (sub-parameters)
  // within single applet parameter value.
  private static final short MaxSubParameters = 9;

  private static final short MaxMenuDepth = 10;

  private char delimiterChar = ';';
  private char escapeChar = '\\';
  private String URLBase = "CODEBASE";

  private String defaultFontName = "Dialog";
  private String defaultFontStyle = "PLAIN";
  private String defaultFontSize = "12";
  private String defaultForegroundColor = "BLACK";
  private String defaultBackgroundColor = "LIGHTGRAY";
  // We don't use "_self" as default because of posibility to improve
  // compatibility with non-frames browsers (HotJava?) by not caling
  // frame-enabled showDocumetn(). I don't know if this is effective.
  private String defaultFrame = null;

  // Selection method constants.
  private static final String smRecursive = "RECURSIVE";
  private static final String smItem = "ITEM";
  private static final String smNone = "NONE";

  private String selectionMode = smRecursive;
  private String selectionFontName = null;
  private String selectionFontStyle = "BOLD";
  private String selectionFontSize = null;

  private String menuActivation = "CLICK";
  private String statusText = null;

  private String menuPosition = "BOTTOM";
  private String missingURL = "ERROR";

  // Used in paint().
  private String labelText = null;
  private Font labelFont = null;
  private Color labelForeground = null;
  private Color labelBackground = null;

  private String mouseoverLabelText = null;
  private Font mouseoverLabelFont = null;
  private Color mouseoverLabelForeground = null;
  private Color mouseoverLabelBackground = null;

  private String clickLabelText = null;
  private Font clickLabelFont = null;
  private Color clickLabelForeground = null;
  private Color clickLabelBackground = null;

  // Button style constants.
  private static final String bsFlat = "FLAT";
  private static final String bsSemiflat = "SEMIFLAT";
  private static final String bsNormal = "NORMAL";

  // Button hover constants.
  private static final String bhHover = "HOVER";
  private static final String bhNohover = "NOHOVER";

  // ButtonStyle = style;hover.
  private String buttonStyle = bsNormal;
  private String buttonHover = bhHover; // Mouseover effect.

  private Image buttonImage = null;
  private Image mouseoverButtonImage = null;
  private Image clickButtonImage = null;

  private static final String bipAbsolute = "ABSOLUTE";
  private static final String bipCenter = "CENTER";
  private static final String bipLeft = "LEFT";
  private static final String bipRight = "RIGHT";
  private static final String bipTop = "TOP";
  private static final String bipBottom = "BOTTOM";

  private String buttonImagePosition = "ABSOLUTE";
  private String buttonImagePositionX = "0";
  private String buttonImagePositionY = "0";
  private String mouseoverButtonImagePosition = null;
  private String mouseoverButtonImagePositionX = null;
  private String mouseoverButtonImagePositionY = null;
  private String clickButtonImagePosition = null;
  private String clickButtonImagePositionX = null;
  private String clickButtonImagePositionY = null;

  // Last selected menu item. Used to improve compatibility
  // with frames. In IE5 this doesn't work.
  PopupNavigatorMenuItem oldSelection = null;

  // Used in loadMenu(). Not static because of multi-use of the same applet
  // in one web page.
  short[] paramCoord = new short[MaxMenuDepth];

  boolean isStandalone = false;
  GridLayout gridLayout1 = new GridLayout();
  PopupMenu popupMenu = new PopupMenu();

  // Get a parameter value. If parameter is not found, def is returned.
  public String getParameter(String key, String def) {
    String tmp;
    tmp = isStandalone ? System.getProperty(key, def) : getParameter(key);
    if (tmp == null)
      tmp = def;
    if (tmp != null)
      tmp = tmp.trim();
    return tmp;
  }

  private Image getImageFromParam(String paramName, Image def) {
    String paramValue;
    paramValue = getParameter(paramName,null);
    if (paramValue == null)
      return def;
    else if (paramValue.length() == 0)
      return null;
    else
      return getImage(encodeURL(paramValue));
  }

  // Returns true if url_string references current domain.
  // Important to avoid unneccessary DNS lookups.
  private boolean isCurrentDomain(final String url_string) {

    // url_string can not be local if it contains "://" or begins with "mailto:".

    String Url = url_string.trim();

    // Strts with "mailto:"?
    if (Url.startsWith("mailto:"))
      return false;


    //for (int i=0; i<Url.length(); ++i) {
    //  if (
    //    Url.charAt(i) == ':'
    //    && i+1 < Url.length()
    //    && Url.charAt(i+1) == '/'
    //    && i+2 < Url.length()
    //    && Url.charAt(i+2) == '/'
    //  ) {
    //} // for search for "://"

    //for (int i = 0; i+2 < Url.length(); ++i) {
    //  if (
    //    Url.charAt(i) == ':'
    //    && Url.charAt(i+1) == '/'
    //    && Url.charAt(i+2) == '/'
    //  ) {
    //} // for search for "://"

    // Contains "://"?
    int i = Url.indexOf("://");
    if (i >= 0) {
      // url_string is not local if its beginning is different then
      // local protocol + local host.
      URL base = getDocumentBase();
      String Protocol = base.getProtocol();
      if (Protocol.equalsIgnoreCase("mailto"))
        Protocol = "mailto:";
      else
        Protocol = Protocol + "://";
      String Host = base.getHost();
      return Url.toLowerCase().startsWith((Protocol + Host).toLowerCase());
    } // if found "://"

    return true;

  } // isCurrentDomain()

  // Returns URL depending on UrlStr parameter and the URLBase parameter.
  private URL encodeURL(String UrlStr) {
    URL base;
    try {
      if (URLBase.equalsIgnoreCase("CODEBASE"))
        base = this.getCodeBase();
      else if (URLBase.equalsIgnoreCase("DOCUMENT"))
        base = this.getDocumentBase();
      else
        base = new URL(URLBase);
      return new URL(base,UrlStr);
    }
    catch (MalformedURLException x) {
      return null;
    }

    /*
    catch (MalformedURLException x) {
      if (!hasErrors) {
        Tokens[0] = formatErrorLabel(
          null,"MALFORMED URL",paramKey.toString(),paramValue);
        hasErrors = true;
      }
    }
    */
  }

  // Decodes semicolon-delimited 'value' and returns array
  // of it's tokens (sub-parameters). StringTokenizer is not
  // used becouse we need support for escape character
  // (backslash). Named sub-parameters will be implemented
  // later. Skipped sub-parameters will be assigned 'Defaults'
  // members with same index. If 'Defaults' is null, then
  // nulls will be assigned to skipped tokens.

  private String[] decodeParamValue(String value, String[] Defaults) throws Exception {

    // TODO: Support for named parameters.

    String[] Tokens = new String[MaxSubParameters];
    int i,currentTokenIndex;

    if (Defaults!=null && Defaults.length>MaxSubParameters)
      throw(new Exception("PopupNavigatorApplet.decodeParamValue() Defaults out of range."));

    StringBuffer currentToken = new StringBuffer();

    for (i=0,currentTokenIndex=0; i<value.length(); ++i) {
      if (value.charAt(i) == escapeChar) {
        ++i;  // Skipping escape.
        if (i<value.length())
          currentToken.append(value.charAt(i)); // Adding character after escape.
      }
      else if (value.charAt(i) == delimiterChar) {
        if (currentToken.length() > 0) { // To leave default or null for skipped sub-parameters.
          Tokens[currentTokenIndex] = currentToken.toString();
          currentToken = new StringBuffer();
        }
        else if (Defaults!=null && currentTokenIndex<Defaults.length) {
          Tokens[currentTokenIndex] = Defaults[currentTokenIndex];
        }
        ++currentTokenIndex;
      }
      else
        currentToken.append(value.charAt(i));
    } // for (iterate through 'value')


    // Last token doesn't need to finish with ';'.
    if (currentToken.length() > 0)  // To leave default or null if last sub-parameter is skipped.
      Tokens[currentTokenIndex++] = currentToken.toString();
    else if (Defaults!=null && currentTokenIndex<Defaults.length) {
      Tokens[currentTokenIndex] = Defaults[currentTokenIndex];
      ++currentTokenIndex;
    }

    // Applying the rest of defaults.
    if (Defaults != null)
      while (currentTokenIndex < Defaults.length) {
        Tokens[currentTokenIndex] = Defaults[currentTokenIndex];
        ++currentTokenIndex;
      }

    return Tokens;

  } // decodeParamValue()



  // Converts string representation of font style to int (as defined
  // in Font class). On failure returns Font.PLAIN - because of
  // robustness.
  private int strToFontStyle(String style) {

    String stylestr = style.toUpperCase();

    //if (stylestr.equals("PLAIN"))
    //  return Font.PLAIN;
    //else
    if (stylestr.equals("BOLD"))
      return Font.BOLD;
    else if (stylestr.equals("ITALIC"))
      return Font.ITALIC;
    else if (stylestr.equals("BOLDITALIC") || stylestr.equals("ITALICBOLD"))
      return Font.BOLD + Font.ITALIC;
    else
      return Font.PLAIN;

  } // strToFontStyle



  private Color strToColor(String value) throws Exception {

    // TODO: Support for system color (CONTROL,...).

    Color result = null;

    // Named color.
    if (Character.isLetter(value.charAt(0))) {
      // We don't want to change 'value'.
      String tmp = value.trim().toUpperCase();  // trim: doesn't change this - returns new string.

      if (tmp.equals("BLACK"))
        result = Color.black;
      else if (tmp.equals("BLUE"))
        result = Color.blue;
      else if (tmp.equals("CYAN"))
        result = Color.cyan;
      else if (tmp.equals("DARKGRAY"))
        result = Color.darkGray;
      else if (tmp.equals("GRAY"))
        result = Color.gray;
      else if (tmp.equals("GREEN"))
        result = Color.green;
      else if (tmp.equals("LIGHTGRAY"))
        result = Color.lightGray;
      else if (tmp.equals("MAGENTA"))
        result = Color.magenta;
      else if (tmp.equals("ORANGE"))
        result = Color.orange;
      else if (tmp.equals("PINK"))
        result = Color.pink;
      else if (tmp.equals("RED"))
        result = Color.red;
      else if (tmp.equals("WHITE"))
        result = Color.white;
      else if (tmp.equals("YELLOW"))
        result = Color.yellow;

      // TODO: Support for system colors.

    } // if named color

    // One integer or space-delimited three-integer color.
    else {
      StringTokenizer st = new StringTokenizer(value," ",false);
      Integer r=null,g=null,b=null;

      if (st.hasMoreTokens()) {
        r = new Integer(st.nextToken());
        if (st.hasMoreTokens()) {
          g = new Integer(st.nextToken());
          if (st.hasMoreTokens())
            b = new Integer(st.nextToken());
        }
      }
      else
        throw new Exception("PopupNavigator.strToColor() Bad color formatting.");

      if (g == null)
        result = new Color(r.intValue()); // r contains whole RGB value.
      else {
        if (b == null)  // Error only b has no value.
          throw new Exception("PopupNavigator.strToColor() Bad color formatting - blue is missing.");
        else // All r, g and b have value.
          result = new Color(r.intValue(),g.intValue(),b.intValue());
      }
    } // else it's number

    return result;

  } // strToColor()

  private boolean strToBoolean(String value) {
    if (value.equalsIgnoreCase("TRUE"))
      return true;
    else
      return false;
  }



  //Construct the applet
  public PopupNavigatorApplet() {
  }



  // Returns Font constructed from begin-th Token (begin, begin+1 and
  // begin+2 contains name, style and size of the font).
  // If Tokens parameter is not sufficient, default values are used:
  // Dialog - PLAIN - 12.
  private Font constructFont(String[] Tokens, int begin) {
    String name = "Dialog";
    int style = Font.PLAIN, size = 12;

    if (Tokens != null) {
      if (Tokens[begin] != null)
        name = Tokens[begin];
      if (Tokens[begin+1] != null)
        style = strToFontStyle(Tokens[begin+1]);
      if (Tokens[begin+2] != null)
        size = new Integer(Tokens[begin+2]).intValue();
    }
    return new Font(name,style,size);
  }



  private String formatErrorLabel(String label, String msg, String paramKey, String paramValue) {
    return
    ((label == null || label.length()==0) ? "" : label + " ")
    + ((msg == null || msg.length()==0) ? "" : msg + " ")
    + "<PARAM NAME=\""
    + ((paramKey == null) ? "null" : paramKey)
    + "\" VALUE=\""
    + ((paramValue == null) ? "null" : paramValue)
    + "\">";
  }



  // Visually distinguishes 'item'. Uses applet-level variable
  // 'selectionMethod' to determine should it recursively
  // distinguish a super-menu.
  private void selectItem(MenuItem item, boolean recursive) {

    if (item instanceof PopupNavigatorMenuItem) {
      PopupNavigatorMenuItem tmpItem = (PopupNavigatorMenuItem)item;
      tmpItem.setFont(new Font(
        (selectionFontName != null) ? selectionFontName : tmpItem.fontName,
        (selectionFontStyle != null) ? strToFontStyle(selectionFontStyle) : tmpItem.fontStyle.intValue(),
        (selectionFontSize != null) ? new Integer(selectionFontSize).intValue() : tmpItem.fontSize.intValue()
      ));
    }
    else if (item instanceof PopupNavigatorMenu) {
      PopupNavigatorMenu tmpMenu = (PopupNavigatorMenu)item;
      tmpMenu.setFont(new Font(
        (selectionFontName != null) ? selectionFontName : tmpMenu.fontName,
        (selectionFontStyle != null) ? strToFontStyle(selectionFontStyle) : tmpMenu.fontStyle.intValue(),
        (selectionFontSize != null) ? new Integer(selectionFontSize).intValue() : tmpMenu.fontSize.intValue()
      ));
    }

    if (
      recursive
      && selectionMode.equalsIgnoreCase(smRecursive)
      && item.getParent() != null
      && item.getParent() instanceof PopupNavigatorMenu
    )
      selectItem((PopupNavigatorMenu)(item.getParent()),true);

  }


  // Uses 'selectionMethod' in the same way as selectItem() does.
  private void deselectItem(MenuItem item, boolean recursive) {

    if (item instanceof PopupNavigatorMenuItem) {
      PopupNavigatorMenuItem tmpItem = (PopupNavigatorMenuItem)item;
      tmpItem.setFont(new Font(
        tmpItem.fontName,
        tmpItem.fontStyle.intValue(),
        tmpItem.fontSize.intValue()
      ));
    }
    else if (item instanceof PopupNavigatorMenu) {
      PopupNavigatorMenu tmpMenu = (PopupNavigatorMenu)item;
      tmpMenu.setFont(new Font(
        tmpMenu.fontName,
        tmpMenu.fontStyle.intValue(),
        tmpMenu.fontSize.intValue()
      ));
    }

    if (
      recursive
      && selectionMode.equalsIgnoreCase(smRecursive)
      && item.getParent()!= null
      && item.getParent() instanceof PopupNavigatorMenu
    )
      deselectItem((PopupNavigatorMenu)(item.getParent()),true);

  }



  // Recursively loads menu-tree with first 'depth' coordinates
  // contained in 'paramCoord' and inserts it as submenu of
  // 'baseMenu'. 'depth' actually contains current level of
  // recursion.
  // Possible return values:
  //   0 - No submenu.
  //   1 - Submenu without selection.
  //   2 - Selected submenu => current item should be also selected.

  private int loadMenu(Menu baseMenu, int depth) {

    int result = 0;

    // Buld non-changing part of parameter key.

    StringBuffer paramKeyStart = new StringBuffer();

    // Current depth ('depth') is excluded.
    for (int i=0; i<depth; ++i) {
      paramKeyStart.append(paramCoord[i]);
      // Delimiter coordinates in non-changing part.
      if (i+1 < depth)
        paramKeyStart.append(delimiterChar);
    }

    // Delimit non-changing and changing part.
    if (paramKeyStart.length() > 0)
      paramKeyStart.append(delimiterChar);

    String paramValue; // Result from getParameter().

    // Iterates through 'depth' level.
    paramCoord[depth] = 0;

    do { // while (paramValue != null);

      // Creating parameter key as semicolon-delimited list of coordinates
      // of current menu item. For example: "1;5;0". We just need to append
      // current depth (contained in 'depth') to precreated non-changing
      // part of key.

      String paramKey = paramKeyStart.toString() + paramCoord[depth];

      // Getting value for current menu item.
      paramValue = getParameter(paramKey.toString(),null);

      if (paramValue != null) { // Item exists.

        if (result==0)
          result = 1; // Maybe will be changed to 2.
        String[] Tokens;

        // To error that occured first.
        boolean hasErrors = false;

        try {
          Tokens = decodeParamValue(paramValue,null);
        } // try
        catch(Exception x) {
          Tokens = new String[MaxSubParameters];
          Tokens[0] = x.toString();
          //Tokens[0] = formatErrorLabel
          //  (null,x.getMessage(),paramKey.toString(),paramValue);
          hasErrors = true;
        }

        // Check for submenus.

        PopupNavigatorMenu tmpMenu = new PopupNavigatorMenu(paramValue);
        int recursiveResult = loadMenu(tmpMenu, depth + 1);

        // Has sub-menus.
        if (recursiveResult > 0) {

          try {

            // 0     1        2         3
            // Label;FontName;FontStyle;FontSize

            // Set font. defaultFontName, defaultFontStyle and defaultFontSize
            // are guarantied not to be null.
            tmpMenu.fontName = (Tokens[1] != null) ? Tokens[1] : defaultFontName;
            tmpMenu.fontStyle = new Integer(strToFontStyle((Tokens[2] != null) ? Tokens[2] : defaultFontStyle));
            tmpMenu.fontSize = new Integer((Tokens[3] != null) ? Tokens[3] : defaultFontSize);

            // Should we select it?
            if (recursiveResult==2) {
              selectItem(tmpMenu,false); // 'false' means non-recursive.
              result = recursiveResult;
            }
            else
              deselectItem(tmpMenu,false);
          }
          catch (Exception x) {
            Tokens = new String[MaxSubParameters];
            //Tokens[0] = x.getMessage();
            Tokens[0] = x.toString();
            //Tokens[0] = formatErrorLabel
            //  (null,x.getMessage(),paramKey.toString(),paramValue);
          }

          // We don't disable it even if it has errors - in order to reach child items.
          tmpMenu.setLabel(Tokens[0]);

          baseMenu.add(tmpMenu);

        } // if has sub-menus

        else { // Menu leaf (hasn't sub-menus).

          // 0     1   2     3        4         5
          // Label;URL;Frame;FontName;FontStyle;FontSize

          // No submenus - we need MenuItem instead of Menu.
          PopupNavigatorMenuItem tmpMenuItem = new PopupNavigatorMenuItem(paramValue);

          try {

            // If it's not a separator (has no label or label is
            // different from "-"), we need url and frame.
            if (Tokens[0]==null || !Tokens[0].equals("-")) {

              // Is URL null?
              if (Tokens[1] == null) {
                if (!hasErrors) {
                  if (missingURL.equalsIgnoreCase("ERROR")) {
                    Tokens[0] = formatErrorLabel(
                      null,"MISSING URL",paramKey.toString(),paramValue);
                    hasErrors = true;
                  }
                  else if (missingURL.equalsIgnoreCase("DISABLE")) {
                    tmpMenuItem.setEnabled(false);
                  }
                }
              }
              else {
                // PREMATURE DNS lookups!
                /*
                URL base;
                try {
                  if (URLBase.equalsIgnoreCase("CODEBASE"))
                    base = this.getCodeBase();
                  else if (URLBase.equalsIgnoreCase("DOCUMENT"))
                    base = this.getDocumentBase();
                  else
                    base = new URL(URLBase);
                  tmpMenuItem.url = new URL(base,Tokens[1]);
                }
                catch (MalformedURLException x) {
                  if (!hasErrors) {
                    Tokens[0] = formatErrorLabel(
                      null,"MALFORMED URL",paramKey.toString(),paramValue);
                    hasErrors = true;
                  }
                }
                */

                if (isCurrentDomain(Tokens[1])) {
                  tmpMenuItem.url = encodeURL(Tokens[1]);
                  if (tmpMenuItem.url == null) {
                    if (!hasErrors) {
                      Tokens[0] = formatErrorLabel(
                        null,"MALFORMED URL",paramKey.toString(),paramValue);
                      hasErrors = true;
                    }
                  }
                }
                else
                  tmpMenuItem.url_string = Tokens[1];

                // Set target frame.
                if (Tokens[2]==null)
                  tmpMenuItem.frame = defaultFrame;
                else
                  tmpMenuItem.frame = Tokens[2];
              } // else url isn't null

              // If label is omitted, use URL as label. We don't need to check
              // for hasErrors because it is false (Tokens[0] wouldn't be null
              // otherwise).
              if ( /*!hasErrors ||*/ Tokens[0] == null)
                Tokens[0] = Tokens[1];

            } // if not separator

            // Set font. defaultFontName, defaultFontStyle and defaultFontSize
            // are guarantied not to be null.
            tmpMenuItem.fontName = (Tokens[3] != null) ? Tokens[3] : defaultFontName;
            tmpMenuItem.fontStyle = new Integer(strToFontStyle((Tokens[4] != null) ? Tokens[4] : defaultFontStyle));
            tmpMenuItem.fontSize = new Integer((Tokens[5] != null) ? Tokens[5] : defaultFontSize);

            // Should we select item?
            if (
              (selectionMode.equalsIgnoreCase(smRecursive) || selectionMode.equalsIgnoreCase(smItem))
              && tmpMenuItem.url != null
              && tmpMenuItem.url.equals(getDocumentBase())
              /*
              && tmpMenuItem.url_string != null
              && sameAsDocumentBase(tmpMenuItem.url_string)
              */
            ) {
              selectItem(tmpMenuItem,false);
              if (selectionMode.equalsIgnoreCase(smRecursive))
                result = 2;
            }
            else
              deselectItem(tmpMenuItem,false);

          }
          catch (Exception x) {
            Tokens = new String[MaxSubParameters];
            //Tokens[0] = x.getMessage();
            Tokens[0] = x.toString();
            //Tokens[0] = formatErrorLabel
            //  (null,x.getMessage(),paramKey.toString(),paramValue);
            hasErrors = true;
          }

          tmpMenuItem.setLabel(Tokens[0]);
          if (hasErrors)
            tmpMenuItem.setEnabled(false);

          baseMenu.add(tmpMenuItem);

        } // else add menu leaf

        ++paramCoord[depth];

      } // if (paramValue != null)

    } while (paramValue != null);

    return result;

  } // loadMenu()

  /*
  // Invalid due Java's stupid parameter passing.
  private void loadLabel(
    String ParamName,
    String[] Default,
    String T,
    Font F,
    Color Fg,
    Color Bg
  ) throws Exception {

    String[] Tokens = decodeParamValue(getParameter("Label", ""),Default);
    T = Tokens[0];
    F = constructFont(Tokens,1); // Font is constructed from tokens: 1 (name), 2 (style) and 3 (size).
    Fg = strToColor(Tokens[4]);
    Bg = strToColor(Tokens[5]);

  }
  */

  // Initialize the applet.
  public void init() {
    try {
      jbInit();

      delimiterChar = getParameter("DelimiterChar", "" + delimiterChar).charAt(0);
      escapeChar = getParameter("EscapeChar", "" + escapeChar).charAt(0);
      URLBase = getParameter("URLBase",URLBase);

      defaultFontName = getParameter("DefaultFontName", defaultFontName);
      defaultFontStyle = getParameter("DefaultFontStyle", defaultFontStyle);
      defaultFontSize = getParameter("DefaultFontSize", defaultFontSize);
      defaultForegroundColor = getParameter("DefaultForegroundColor", defaultForegroundColor);
      defaultFrame = getParameter("DefaultFrame");

      String[] Tokens;

      // Setup button appearance.
      Tokens = decodeParamValue(
        getParameter("Label", ""),
        new String[] {null,defaultFontName,defaultFontStyle,
          defaultFontSize,defaultForegroundColor,defaultBackgroundColor}
      );
      if (Tokens[0] == null) {
        if (getParameter("Label",null) == null)
          Tokens[0] = "Navigate";
        else
          Tokens[0] = "";
      }
      labelText = Tokens[0];
      labelFont = constructFont(Tokens,1); // Font is constructed from tokens: 1 (name), 2 (style) and 3 (size).
      labelForeground = strToColor(Tokens[4]);
      labelBackground = strToColor(Tokens[5]);

      Tokens = decodeParamValue(
        getParameter("MouseoverLabel", ""),
        Tokens
      );
      mouseoverLabelText = Tokens[0];
      mouseoverLabelFont = constructFont(Tokens,1); // Font is constructed from tokens: 1 (name), 2 (style) and 3 (size).
      mouseoverLabelForeground = strToColor(Tokens[4]);
      mouseoverLabelBackground = strToColor(Tokens[5]);

      Tokens = decodeParamValue(
        getParameter("ClickLabel", ""),
        Tokens
      );
      clickLabelText = Tokens[0];
      clickLabelFont = constructFont(Tokens,1); // Font is constructed from tokens: 1 (name), 2 (style) and 3 (size).
      clickLabelForeground = strToColor(Tokens[4]);
      clickLabelBackground = strToColor(Tokens[5]);

      // Mouseover (hover) effect.
      Tokens = decodeParamValue(
        getParameter("ButtonStyle", ""),
        new String[] {buttonStyle,buttonHover}
      );
      buttonStyle = Tokens[0];
      buttonHover = Tokens[1];

      // Selection distinguishing.
      Tokens = decodeParamValue(
        getParameter("Selection", ""),
        new String[] {selectionMode,selectionFontName,selectionFontStyle,selectionFontSize}
      );
      selectionMode = Tokens[0];
      selectionFontName = Tokens[1];
      selectionFontStyle = Tokens[2];
      selectionFontSize = Tokens[3];

      menuActivation = getParameter("MenuActivation",menuActivation);

      // TODO: Show URL in status-bar.
      statusText = getParameter("StatusText",statusText);

      menuPosition = getParameter("MenuPosition",menuPosition);
      missingURL = getParameter("MissingURL",missingURL);

      // Load button images.
      buttonImage = getImageFromParam("Image",null);
      mouseoverButtonImage = getImageFromParam("MouseoverImage",buttonImage);
      clickButtonImage = getImageFromParam("ClickImage",mouseoverButtonImage);

      // Load button image positions.
      Tokens = decodeParamValue(
        getParameter("ImagePosition", ""),
        new String[] {buttonImagePosition,buttonImagePositionX,buttonImagePositionY}
      );
      buttonImagePosition = Tokens[0];
      buttonImagePositionX = Tokens[1];
      buttonImagePositionY = Tokens[2];

      Tokens = decodeParamValue(
        getParameter("MouseoverImagePosition", ""),
        Tokens
      );
      mouseoverButtonImagePosition = Tokens[0];
      mouseoverButtonImagePositionX = Tokens[1];
      mouseoverButtonImagePositionY = Tokens[2];

      Tokens = decodeParamValue(
        getParameter("ClickImagePosition", ""),
        Tokens
      );
      clickButtonImagePosition = Tokens[0];
      clickButtonImagePositionX = Tokens[1];
      clickButtonImagePositionY = Tokens[2];

      //buttonImagePosition = getParameter("ImagePosition",buttonImagePosition);
      //mouseoverButtonImagePosition = getParameter("MouseoverImagePosition",mouseoverButtonImagePosition);
      //clickButtonImagePosition = getParameter("ClickImagePosition",clickButtonImagePosition);

      //buttonImage = getImageFromParam("ButtonImage");
      //buttonHoverImage = getImageFromParam("ButtonHoverImage");
      //buttonDownImage = getImageFromParam("ButtonDownImage");

      // Load menu.
      loadMenu(popupMenu,0);

      enableEvents(AWTEvent.MOUSE_EVENT_MASK);

    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }



  // Component initialization.
  private void jbInit() throws Exception {
    this.setLayout(gridLayout1);
    //menuButton.setLabel("MenuButton");
    /*
    menuButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        menuButton_actionPerformed(e);
      }
    });
    */
    //this.setSize(400,300);
    //this.setSize(MenuButton.getBounds().width+2,MenuButton.getBounds().height+2);
    //menuButton.requestFocus();
    //this.add(menuButton, null);
    this.add(popupMenu);
  }

  public void showPopupMenu() {
    int x,y;
    if (menuPosition.equalsIgnoreCase("RIGHT")) {
      //x = menuButton.getBounds().width;
      x = getBounds().width;
      y = 0;
    }
    else { //if menuPosition.equalsIgnoreCase("BOTTOM")
      x = 0;
      //y = menuButton.getBounds().height;
      y = getBounds().height;
    }
    //popupMenu.show(menuButton,x,y);
    popupMenu.show(this,x,y);
  }

  public boolean action(Event evt, Object arg) {

    //if (evt.target instanceof Button)
    //  showPopupMenu();
    //if (evt.target instanceof Applet)
    //  showPopupMenu();
    //else
    if (evt.target instanceof PopupNavigatorMenuItem) {
      PopupNavigatorMenuItem source = (PopupNavigatorMenuItem)(evt.target);
      switch(evt.id) {
        case Event.ACTION_EVENT:
          navigate(source);
          return true;
          //break;
        // PopupMenu currently doesn't support mouse events.
        //case Event.MOUSE_ENTER:
        //  showStatus(source.url.toString());
        //  break;
        default:
          return false;
      }
    }

    return false;

    // Because of stupid compiler.
    //return true;
  }


  protected void processMouseEvent(MouseEvent e) {
    super.processMouseEvent(e);
    switch (e.getID()) {
      case MouseEvent.MOUSE_ENTERED:
        mouseIn = true;
        if (statusText != null)
          showStatus(statusText);
        if (menuActivation.equalsIgnoreCase("MOUSEOVER"))
          showPopupMenu();
        // TODO: Check is repainting is necessary.
        repaint();
        break;
      case MouseEvent.MOUSE_EXITED:
        if (statusText != null)
          showStatus("");
        //mouseDown = false;
        mouseIn = false;
        repaint();
        break;
      case MouseEvent.MOUSE_PRESSED:
        mouseDown = true; // mouseIn is irelevant.
        repaint();
        break;
      case MouseEvent.MOUSE_RELEASED:
        mouseDown = false; // mouseIn is irelevant.
        if (
          e.getX() >= getBounds().x
          && e.getY() >= getBounds().y
          && e.getX() <= getBounds().x + getBounds().width
          && e.getY() <= getBounds().y + getBounds().height
        )
          showPopupMenu();
        else
          mouseIn = false; // Some browsers could avoid delivering MOUSE_EXITED event.
        repaint();
        break;
      case MouseEvent.MOUSE_CLICKED:
        break;
    }
  }


  //Get Applet information
  public String getAppletInfo() {
    return "PopupNavigatorApplet by Branko Dimitrijevic";
  }



  //Get parameter info
  //public String[][] getParameterInfo() {
  //  return null;
  //}



  //void menuButton_actionPerformed(ActionEvent e) {
  //  popupMenu.show(menuButton,0,menuButton.getBounds().height);
  //}



  private void navigate(PopupNavigatorMenuItem item) {

    if (selectionMode.equalsIgnoreCase(smRecursive)) {
      if (oldSelection != null)
        deselectItem(oldSelection,true);
      oldSelection = item;
      selectItem(item,true);
    }
    else if (selectionMode.equalsIgnoreCase(smItem)) {
      if (oldSelection != null)
        deselectItem(oldSelection,false);
      oldSelection = item;
      selectItem(item,false);
    }

    if (item.url == null)
      item.url = encodeURL(item.url_string);

    if (item.frame == null)
      getAppletContext().showDocument(item.url);
    else
      getAppletContext().showDocument(item.url,item.frame);

  } // navigate()

  //void onNavigationStart(ActionEvent e) {
  //  PopupNavigatorMenuItem source = (PopupNavigatorMenuItem)(e.getSource());
  //  navigate(source);
  //}

  //private void paintImage(Graphics g, Image img, String pos, String posX, String posY) {

  //  if buttonImagePosition.equalsIgnoreCase(bipAbsolute)

  //  g.drawImage(
  //    img,
  //    new Integer(posX).intValue(),
  //    new Integer(posY).intValue(),
  //    this
  //  );
  //}

  // Paints label.
  private void paintLabelAndImage(
    Graphics g,
    Color background,
    Color foreground,
    Font f,
    String text,
    Image img,
    String pos,  // ABSOLUTE, CENTER, RIGHT,...
    String posX,
    String posY
  ) {

    // Draw background.
    g.setColor(background);
    g.fillRect(0,0,getBounds().width,getBounds().height);

    g.setFont(f);
    FontMetrics FM = g.getFontMetrics(g.getFont());

    int appletWidth = getBounds().width;
    int appletHeight = getBounds().height;

    // TODO: Label position.

    // Calculate label coordinates.
    int labelWidth;
    if (text == null)
      labelWidth = 0;
    else
      labelWidth = FM.stringWidth(text);
    int labelX = (appletWidth  - labelWidth) / 2;
    int labelY = (appletHeight - FM.getDescent() + FM.getAscent()) / 2;

    // Calculate image, possibly change label coordinates and draw image.
    if (img != null) {

      int imageWidth = img.getWidth(this);
      int imageHeight = img.getHeight(this);

      // Image loaded?
      if (imageWidth > 0 && imageHeight > 0) {

        int imageX,imageY;

        if (pos.equalsIgnoreCase(bipAbsolute)) {
          imageX = new Integer(posX).intValue();
          if (imageX < 0)
            imageX = appletWidth + imageX - imageWidth;
          imageY = new Integer(posY).intValue();
          if (imageY < 0)
            imageY = appletHeight + imageY - imageHeight;
        }
        else if (pos.equalsIgnoreCase(bipCenter)) {
          imageX = (appletWidth - imageWidth) / 2;
          imageY = (appletHeight - imageHeight) / 2;
        }
        else if (pos.equalsIgnoreCase(bipLeft) || pos.equalsIgnoreCase(bipRight)) {
          int a = new Integer(posX).intValue();
          if (pos.equalsIgnoreCase(bipLeft)) {
            labelX += a/2;
            imageX = labelX - a - imageWidth;
          }
          else { // pos.equalsIgnoreCase(bipRight)
            labelX -= a/2;
            imageX = labelX + labelWidth + a;
          }
          imageY = (appletHeight - imageHeight) / 2;
        }
        else if (pos.equalsIgnoreCase(bipTop) || pos.equalsIgnoreCase(bipBottom)) {
          int a = new Integer(posX).intValue();
          if (pos.equalsIgnoreCase(bipTop)) {
            labelY += a/2 ;
            imageY = labelY - FM.getAscent() - a - imageHeight;
          }
          else { //pos.equalsIgnoreCase(bipTop);
            labelY -= a/2;
            imageY = labelY + FM.getDescent() + a;
          }
          imageX = (appletWidth - imageWidth) / 2;
        }
        else { // For robustness.
          imageX = 0;
          imageY = 0;
        }

        // Draw image.
        g.drawImage(img,imageX,imageY,this);

      } // if image loaded

    } // if (img != null)

    // Draw label.
    if (text != null) {
      g.setColor(foreground);
      g.drawString(
        text,
        labelX,
        labelY
      );
    }

  }

  private void paint3dRect(
    Graphics g,
    int x,
    int y,
    int w,
    int h,
    Color C1, // Light color.
    Color C2, // Dark color.
    boolean raised
  ) {
    if (!raised) {
      Color Tmp = C1;
      C1 = C2;
      C2 = Tmp;
    }
    g.setColor(C1);
    g.drawLine(x,y,w,y);
    g.drawLine(x,y,x,h);
    g.setColor(C2);
    g.drawLine(w,y,w,h);
    g.drawLine(x,h,w,h);
  }

  private void paintThinBorder(Graphics g, boolean raised) {
    paint3dRect(
      g,
      0,
      0,
      getBounds().width - 1,
      getBounds().height - 1,
      Color.white,
      Color.gray,
      raised
    );
  }

  private void paintNormalBorder(Graphics g, boolean raised) {
    paint3dRect(
      g,
      1,
      1,
      getBounds().width - 2,
      getBounds().height - 2,
      Color.lightGray,
      Color.gray,
      raised
    );
    paint3dRect(
      g,
      0,
      0,
      getBounds().width - 1,
      getBounds().height - 1,
      Color.white,
      Color.darkGray,
      raised
    );
  }

  private void paintThickBorder(Graphics g, boolean raised) {
    paint3dRect(
      g,
      2,
      2,
      getBounds().width - 3,
      getBounds().height - 3,
      Color.lightGray,
      Color.gray,
      raised
    );
    paint3dRect(
      g,
      1,
      1,
      getBounds().width - 2,
      getBounds().height - 2,
      Color.white,
      Color.darkGray,
      raised
    );
    g.setColor(Color.black);
    g.drawRect(0,0,getBounds().width-1,getBounds().height-1);
  }

  private void paintButtonBorder(Graphics g, boolean raised) {
    if (buttonStyle.equalsIgnoreCase(bsSemiflat))
      paintThinBorder(g,raised);
    else if (buttonStyle.equalsIgnoreCase(bsNormal))
      paintNormalBorder(g,raised);
  }

  private void paintHoverBorder(Graphics g, boolean raised) {
    if (buttonStyle.equalsIgnoreCase(bsFlat))
      paintThinBorder(g,raised);
    else if (buttonStyle.equalsIgnoreCase(bsSemiflat))
      paintNormalBorder(g,raised);
    else if (buttonStyle.equalsIgnoreCase(bsNormal))
      paintThickBorder(g,raised);
  }

  // TODO: Support for oval button border.

  public void paint(Graphics g) {
    //g.drawLine(1,1,10,10);
    //g.drawString("history", 10, 10);

    // Draw background.
    //g.setColor(labelBackground);
    //g.fillRect(0,0,getBounds().width,getBounds().height);

    // Draw label.
    //g.setFont(labelFont);
    //g.setColor(labelForeground);
    //FontMetrics FM = g.getFontMetrics(g.getFont());
    //g.drawString(
    //  labelText,
    //  (getBounds().width - FM.stringWidth(labelText)) / 2,
    //  (getBounds().height - FM.getDescent() + FM.getAscent()) / 2
    //);

    // Draw border.
    if (mouseDown) {
      paintLabelAndImage(
        g,clickLabelBackground,clickLabelForeground,clickLabelFont,clickLabelText,
        clickButtonImage,clickButtonImagePosition,clickButtonImagePositionX,clickButtonImagePositionY
      );
      if (buttonHover.equalsIgnoreCase(bhHover))
        paintHoverBorder(g,false);
      else
        paintButtonBorder(g,false);
    }
    else if (mouseIn) {
      paintLabelAndImage(
        g,mouseoverLabelBackground,mouseoverLabelForeground,mouseoverLabelFont,mouseoverLabelText,
        mouseoverButtonImage,mouseoverButtonImagePosition,mouseoverButtonImagePositionX,mouseoverButtonImagePositionY
      );
      if (buttonHover.equalsIgnoreCase(bhHover))
        paintHoverBorder(g,true);
      else
        paintButtonBorder(g,true);
    }
    else {
      paintLabelAndImage(
        g,labelBackground,labelForeground,labelFont,labelText,
        buttonImage,buttonImagePosition,buttonImagePositionX,buttonImagePositionY
      );
      paintButtonBorder(g,true);
    }
    //paintThickBorder(g,!mouseDown);
    //paintImage(g,buttonImage,buttonImagePosition,buttonImagePositionX,buttonImagePositionY);

  } // paint

} // SiteMenuBarApplet

Back to PopupNavigator

How to Add Java Applets to Your Site

New on the Java Boutique:

New Review:

Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling API boasts simplicity, ease-of-integration, a well-rounded feature set, and it's free!

New Applet:

Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA sequences into three useful formats.

Elsewhere on internet.com:

WebDeveloper Java
Lots of Java information on webdeveloper.com

WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.

ScriptSearch Java
Hundreds of free Java code files to download.

jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.

 Microsoft RIA Development Center
 IBM Rational Resource Center
 Destination .NET
XML error: not well-formed (invalid token) at line 33
advertisement
Receive Articles via our XML/RSS feed
Receive Articles via our XML/RSS feed

JavaBytes
Internet Cyclone
This powerful, easy-to-use, internet optimizer is for Windows 95, 98, ME, NT, 2000 and XP. It's designed to automatically optimize your Windows settings, boosting your Internet connection up to 200%.

Linux Player Xandros Grabs Storied Rival Linspire
Hey Enterprise: Here Comes the 3G iPhone
MySpace Opens Profile Portability API
Microsoft Jumps Into Virtualization Fray
Eclipse Ganymede Makes It Easier for Devs
Open Source Nokia a Threat to Microsoft, Google?
Salesforce, Google Head for 2nd on Apps
HP Open Sources Unix File System for Linux
Red Hat Opens Its Network to Space
Novell: openSUSE for All Linux Users

Beyond XML and JSON: YAML for Java Developers
Mastering the Windows Mobile Emulators
Avaya AE Services Provide Rapid Telephony Integration with Facebook
Featured Algorithm: Intel Threading Building Blocks: parallel_reduce
Getting Started with Windows Live Admin Center
Eight Key Practices for ASP.NET Deployment
Java ME User Interfaces: Do It with LWUIT!
Talking VPro: Transcript
Bringing Semantic Technology to the Enterprise
Persisting Data in Your Windows Mobile Device

Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map  |   Network Map  |   About



JupiterOnlineMedia

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info


Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

Solutions
Whitepapers and eBooks
IBM eBook: Planning a Service Oriented Architecture
IBM eBook: Choosing the Right Architecture--What It Means for You and Your Business
Microsoft Article: Will Hyper-V Make VMware This Decade's Netscape?
Avaya Article: Using Intelligent Presence to Create Smarter Business Applications
Intel Go Parallel Article: Getting Started with TBB on Windows
Microsoft Article: 7.0, Microsoft's Lucky Version?
Avaya Article: How to Feed Data into the Avaya Event Processor
IBM Article: Developing a Software Policy for Your Organization
Microsoft Article: Managing Virtual Machines with Microsoft System Center
Intel Go Parallel Article: Intel Threading Tools and OpenMP
HP eBook: Storage Networking , Part 1
Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
MORE WHITEPAPERS, EBOOKS, AND ARTICLES
Webcasts
HP Video: StorageWorks EVA4400 and Oracle
HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
MORE WEBCASTS, PODCASTS, AND VIDEOS
Downloads and eKits
Red Gate Download: SQL Toolbelt and free High-Performance SQL Code eBook
Iron Speed Designer Application Generator
MORE DOWNLOADS, EKITS, AND FREE TRIALS
Tutorials and Demos
Silverlight 2 App and Walkthrough: Leverage Silverlight 2 with SQL Server and XML
IBM Article: Enterprise Search--Do You Know What's Out There?
HP Demo: StorageWorks EVA4400
Microsoft Article: The Progress and Promise of Deep Zoom
Microsoft How-to Article: Get Going with Silverlight and Windows Live
MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES