/*
 * Analyzer.java
 *
 * Copyright (c) 2003, Oracle Corporation. All rights reserved. Oracle grants
 * you ("Licensee") a non-exclusive, royalty-free, worldwide license to use,
 * modify and redistribute this software in source and binary code form, provided
 * that (i) this copyright notice and license appear on all copies of the
 * software; (ii) Licensee does not utilize the software in a manner disparaging
 * to Oracle; and (iii) Licensee does not utilize the software in a manner that
 * violates the terms of any Licensee agreement with Oracle.
 */
package samples.javaclient.analyzer;

import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import oracle.dss.persistence.PSRConstants;
import javax.swing.JOptionPane;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import java.lang.Double;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JSplitPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
import javax.swing.tree.TreePath;

import oracle.bali.ewt.olaf.OracleBorderFactory;
import oracle.bali.ewt.statusBar.StatusBar;
import oracle.bali.ewt.util.WindowUtils;
import oracle.bali.share.nls.StringUtils;

import oracle.dss.dataSource.client.QueryClient;
import oracle.dss.dataView.Dataview;
import oracle.dss.graph.gui.GraphToolBar;
//import oracle.dss.dataView.gui.ToolBar;
import oracle.dss.graph.Graph;
import oracle.dss.gridView.gui.DecimalTool;
import oracle.dss.gridView.gui.NumberTypeTool;

/**
 * The main class for the Ad Hoq Analysis Tool sample application.
 * This class constructs the user interface for the application. 
 * The main user interface includes:
 * <ul>
 * <li>A desktop, which can contain multiple 
 *     {@link Worksheet} objects</li>
 * <li>A {@link Sidebar}, which contains three Explorers:
 *    <ul><li>A {@link CatalogExplorer}, which presents worksheets</li>
 *        <li>A {@link FavoritesExplorer}, which presents saved selections</li>
 *        <li>A {@link DimensionExplorer}, which presents members of different 
 *            dimensions</li></ul></li>
 * <li>A menu bar</li>
 * <li>A toolbar</li>
 * <li>A status bar</li>
 * </ul>
 * This class also instantiates an {@link AnalyzerConnection} for the
 * application, and it uses the connection for access to managers that
 * the application needs, such as the MetadataManager and the QueryManager.
 * <p>
 * Crosstabs and graphs that users create in Analyzer are contained in 
 * Worksheet objects.
 * <p>
 * This class listens for clicks in the menus and toolbars, and it calls
 * methods that respond to those clicks.
 * For example, choosing the New item on the File menu brings up a
 * {@link NewPresentationWizard}.
 * This class instantiates that wizard object and runs it.
 * <p>
 * This class has support for drag-and-drop in its implementation of the 
 * DropTargetListener interface.
 * In its implementation of the InternalFrameListener interface, this
 * class supports a multiple-document interface.
 * 
 */
public class Analyzer extends JFrame
       implements DropTargetListener, InternalFrameListener, ActionListener {
  /*
   * Strings used in main application
   */
  /**
   * Version of this sample application.
   */
  private static final String VERSION = "1.0.8";

  /**
   * Application title: "BI Beans Sample - Ad Hoc Analysis Tool".
   * This constant is passed to the constructor for this class in the
   * main method.
   * @see #main
   */
  private static final String TITLE = "BI Beans Sample - Ad Hoc Analysis Tool";

  /**
   * The title of a new worksheet: "Untitled".
   * @see #newPresentation
   */
  private static final String UNTITLED = "Untitled";

  /**
   * The title of the Worksheet Explorer: "Worksheets".
   * This constant is passed to the constructor for WorksheetExplorer.
   * @see #jbInit
   */
  private static final String WORKSHEET_EXPLORER = "Worksheets";

  /**
   * The title of the Favorites Explorer: "Saved Selections".
   * This constant is passed to the constructor for FavoritesExplorer.
   * @see #jbInit
   */
  private static final String FAVORITES_EXPLORER = "Saved Selections";

  /**
   * The title of the Dimension Explorer: "Members".
   * This constant is passed to the constructor for DimensionExplorer.
   * @see #jbInit
   */
  private static final String DIMENSION_EXPLORER = "Members";

  /*
   * "/analyzer.xml" -- not used
  private static final String m_configFile = "/analyzer.xml";
   */

  /**
   * File menu: "&File".
   * @see #jbInit
   */
  private static final String FILE = "&File";

  /**
   * Tools menu: "&Tools".
   * @see #jbInit
   */
  private static final String TOOLS = "&Tools";

  /**
   * Help menu: "&Help".
   * @see #jbInit
   */
  private static final String HELP = "&Help";

  /**
   * About item on the Help menu: "&About".
   * @see #jbInit
   */
  private static final String HELP_ABOUT = "&About";

  /**
   * New item on the File menu: "&New...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String FILE_NEW = "&New...";

  /**
   * Open item on the File menu: "&Open...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String FILE_OPEN = "&Open...";

  /**
   * Save item on the File menu: "&Save".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String FILE_SAVE = "&Save";

  /**
   * Save As item on the File menu: "Save &As...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String FILE_SAVEAS = "Save &As...";

  /**
   * Print item on the File menu: "&Print...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String FILE_PRINT = "&Print...";

  /**
   * Export item on the File menu: "&Export...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String FILE_EXPORT = "&Export...";

  /**
   * Connect item on the File menu: "&Connect...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String FILE_CONNECT = "&Connect...";

  /**
   * Disconnect item on the File menu: "&Disconnect...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String FILE_DISCONNECT = "&Disconnect...";

  /**
   * Exit item on the File menu: "E&xit...".
   * @see #jbInit
   * @see #exit
   * @see #actionPerformed
   */
  private static final String FILE_EXIT = "E&xit";

  /**
   * Window menu: "&Window".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String WINDOW = "&Window";

  /**
   * Tile Horizontal item on the Window menu: "Tile &Horizontal".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String TILE_HORIZONTAL = "Tile &Horizontal";

  /**
   * Tile Vertical item on the Window menu: "Tile &Vertical".
   * @see #actionPerformed
   * @see #jbInit
   */
  private static final String TILE_VERTICAL = "Tile &Vertical";

  /**
   * Edit Query item on the Tools menu: "Edit &Query...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String TOOLS_QB = "Edit &Query...";

  /**
   * Insert Calculation item on the Tools menu: "Insert &Calculation...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String TOOLS_CB = "Insert &Calculation...";

  /**
   * Graph Type item on the Tools menu: "&Graph Type...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String TOOLS_GRAPHTYPE = "&Graph Type...";

  /**
   * Format Graph item on the Tools menu: "&Format Graph...".
   * @see #jbInit
   * @see #actionPerformed
   */
  private static final String TOOLS_FORMATGRAPH = "&Format Graph...";

  /**
   * View menu: "&View".
   * @see #jbInit
   */
  private static final String VIEW = "&View";

  /**
   * View type: Graph.
   * Label for the Graph item on the View menu: "&Graph".
   * Also identifies the graph view type in the view type tool in the toolbar.
   * @see #jbInit
   * @see #actionPerformed
   * @see #setDataviewType
   */
  public static final String VIEW_GRAPH = "&Graph";

  /**
   * View type: Crosstab.
   * Label for the Crosstab item on the View menu: "&Crosstab".
   * Also identifies the crosstab view type in the view type tool in the toolbar.
   * @see #jbInit
   * @see #actionPerformed
   * @see #setDataviewType
   */
  public static final String VIEW_CROSSTAB = "&Crosstab";

  /**
   * Status: Connected.
   * The status bar displays this message when a connection is successful.
   * 
   * @see #enableMenus
   */
  private static final String CONNECTED = "Connected";

  /**
   * Status: Not connected.
   * The status bar displays this message before a connection is made and
   * when a connection attempt is unsuccessful.
   * @see #jbInit
   * @see #enableMenus
   */
  private static final String NOT_CONNECTED = "Not connected";

  /**
   * Status: Attemping to connect.
   * The status bar displays this message during a connection attempt.
   * @see #jbInit
   */
  private static final String ATTEMPT_CONNECT = "Attempting to connect...";


  /*
   * Member variables that cache references to key objects
   */
  /**
   * Do we automatically connect to the database?
   */
  private boolean m_autoconnect = false;        // Autoconnect to the database?

  /**
   * Active worksheet.
   */ 
  private Worksheet m_worksheet;                // Currently selected worksheet - or document

  /**
   * Desktop. 
   * The desktop is the area where worksheets appear. 
   * The desktop and the sidebar are contained in a splitter.
   * @see #jbInit
   */
  private JDesktopPane m_desktop;               // Area that contains the worksheets

  /**
   * Toolbar.
   * The toolbar is a GraphToolBar with some added tools.
   * @see #jbInit
   * @see #enableMenus
   */
  private GraphToolBar m_toolBar = new GraphToolBar();     // Application toolbar

  /**
   * Text for the status bar.
   */
  private JLabel m_statusText = new JLabel();   // the status for the application

  /**
   * The status bar.
   */
  private StatusBar m_statusBar;                // status bar found at the bottom of the app

  /**
   * The sidebar.
   * The sidebar is a JPanel for the Explorers.
   * The sidebar and the desktop are contained in a splitter.
   * 
   * @see #jbInit
   * @see CatalogExplorer
   * @see DimensionExplorer
   * @see FavoritesExplorer
   */
  private Sidebar m_sidebar;                    // Panel used to show list of reports, dimlist

  /**
   * The worksheet explorer, where users can select the active worksheet.
   * This explorer is contained in the sidebar.
   * @see #jbInit
   */
  private CatalogExplorer m_worksheetExplorer;  // Explorer that contains list of worksheets
  
  /**
   * The favorites explorer, where users can select saved selections and
   * drag them to a view.
   * @see #jbInit
   */
  private FavoritesExplorer m_favoritesExplorer; // Explorer that contains list of favorites (saved selections)

  /**
   * The dimension explorer, where users can select dimension members and
   * drag them to a view.
   * @see #jbInit
   */
  private DimensionExplorer m_dimensionExplorer; // Explorer that contains dimension members

  /**
   * Splitter that contains the sidebar and the desktop.
   * @see #jbInit
   */
  private JSplitPane m_splitpane;               // splitter between Explorer and Desktop area

  /**
   * AnalyzerConnection, which encapsulates information about connections.
   * @see #Analyzer
   * @see #jbInit
   * @see #initializeUI
   * @see #showConnectDialog
   * @see #showDisconnectDialog
   * @see #newPresentation
   * @see #enableMenus
   * @see #getConnection
   * @see #exit
   */
  private AnalyzerConnection m_connection;      // Analyzer Connection information

  /**
   * Analyzer utilities, which displays dialogs, runs the QueryBuilder and
   * the CalcBuilder, and handles errors.
   */ 
  private AnalyzerUtilities m_util;             // Utilities for displaying dialogs, etc.

  /*
   * Menus
   */
  /**
   * The menu bar.
   */
  private JMenuBar m_menubar = new JMenuBar();

  /**
   * File menu.
   * @see #jbInit
   */
  private JMenu m_mnuFile = new JMenu();

  /**
   * New item in File menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuNew = new JMenuItem();

  /**
   * Open item in File menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuOpen = new JMenuItem();

  /**
   * Save item in File menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuSave = new JMenuItem();

  /**
   * Save As item in File menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuSaveAs = new JMenuItem();

  /**
   * Print item in File menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuPrint = new JMenuItem();
 
  /**
   * Export item in File menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuExport = new JMenuItem();

  /**
   * Connect item in File menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuConnect = new JMenuItem();

  /**
   * Disconnect item in File menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuDisconnect = new JMenuItem();

  /**
   * Exit item in File menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuExit = new JMenuItem();

  /**
   * Tools menu.
   * @see #jbInit
   */
  private JMenu m_mnuTools = new JMenu();

  /**
   * Edit Query item on the Tools menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuQB = new JMenuItem();

  /**
   * Insert Calculation item on the Tools menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuCB = new JMenuItem();

  /**
   * Graph Type item on the Tools menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuGraphType = new JMenuItem();

  /**
   * Format Graph item on the Tools menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuFmtGraph = new JMenuItem();

  /**
   * Window menu.
   * @see #jbInit
   */
  private JMenu m_mnuWindow = new JMenu();

  /**
   * Tile Horizontal item on the Window menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuHorizontal = new JMenuItem();

  /**
   * Tile Vertical item on the Window menu.
   * @see #jbInit
   */
  private JMenuItem m_mnuVertical = new JMenuItem();

  /**
   * View menu.
   * @see #jbInit
   */
  private JMenu m_mnuView = new JMenu();

  /**
   * Graph item on the View menu.
   * @see #jbInit
   */
  private JRadioButtonMenuItem m_mnuGraph = new JRadioButtonMenuItem();

  /**
   * Crosstab item on the View menu.
   * @see #jbInit
   */
  private JRadioButtonMenuItem m_mnuCrosstab = new JRadioButtonMenuItem();

  /**
   * Help menu.
   * @see #jbInit
   */
  private JMenu m_mnuHelp = new JMenu();

  /**
   * About item on the Help menu.
   * @see #jbInit
   */
  private JMenuItem m_aboutMenu = new JMenuItem();

  /*
   * Toolbar buttons
   */
  /**
   * New button for toolbar.
   * @see #jbInit
   */
  private JButton btnNew;
  /**
   * Open button for toolbar.
   * @see #jbInit
   */
  private JButton btnOpen;
  /**
   * Edit button for toolbar.
   * @see #jbInit
   */
  private JButton btnEdit;
  /**
   * Calculation button for toolbar.
   * @see #jbInit
   */
  private JButton btnCB;
  /**
   * QueryBuilder button for toolbar.
   * @see #jbInit
   */
  private JButton btnQB;
  /**
   * Print button for toolbar.
   * @see #jbInit
   */
  private JButton btnPrint;
  /**
   * Save button for toolbar.
   * @see #jbInit
   */
  private JButton btnSave;
  
  /**
   * Graph button for toolbar.
   * @see #jbInit
   */
  private JToggleButton btnGraph;
  
  /**
   * Crosstab button for toolbar.
   * @see #jbInit
   */
  private JToggleButton btnCrosstab;

  /*
   * Listeners
   */
  /**
   * Listener for changes made to a view through the toolbar.
   */
  private ToolbarFormatListener m_toolbarFormatListener;
  /**
   * Listener for mouse clicks in the Catalog Explorer.
   */
  private MouseAdapter m_catalogListener;
  /**
   * Listener for mouse clicks in views.
   */
  private MouseAdapter m_viewMouseListener;

  // Application class
  /**
   * Application class.
   */
  private Analyzer m_analyzer;

  /**
   * Sets the initial look and feel for the application.
   */
  static {
    try  {
      // We use the Oracle Browser Look and Feel by default
      // Try different default look and feels here
      oracle.bali.ewt.olaf.BrowserLookAndFeel olaf = new oracle.bali.ewt.olaf.BrowserLookAndFeel();
      UIManager.setLookAndFeel(olaf);
    }
    catch (Exception e) {}
  }

  /**
   * Constructor for Analyzer.  The application starts in one of two ways:
   * <ol>
   * <li>Prompts the user for database connection details.</li>
   * <li>Automatically connects to the database based on settings found in the
   * AnalyzerTemplate.XML file.  To change the autoconnect settings, simply update the
   * information using the Settings menu item on the BIDesigner in JDeveloper.
   * </ol>
   *
   * @param title The title of the JFrame.
   * @param autoConnect Should the application automatically connect to the database?
   *                    Pass "autoconnect" to have the application use
   *                    parameters in analyzerTemplate.xml.
   *                    By default, the application prompts the user for
   *                    connection details.
   */
  public Analyzer(String title, String autoConnect) {
    super(title);
    m_analyzer = this;

    jbInit();

    setSize(800, 600);

    setVisible(true);
    /*
     * Automatically display the connect dialog if the command line argument
     * autoconnect was passed
     */
    if (autoConnect.equalsIgnoreCase("autoconnect")) {
      setStatusBarMessage(ATTEMPT_CONNECT);
      boolean isConnected = m_connection.autoConnect();

      // Update the Explorers and the menus/toolbars
      initializeUI();

      if (isConnected) {
        m_autoconnect = true;

        /* Automatically display the dialog that asks whether the user wants to
         * create a New Worksheet or Open an Existing Worksheet
         */
        NewOrOpenWizard noow = new NewOrOpenWizard();
        noow.setCenterOver(this);
        boolean isOK = noow.runDialog();

        // If the user Okay'ed, then perform the appropriate action
        if (isOK){
          String action = noow.getSelectedAction();
          if (action.equalsIgnoreCase(NewOrOpenWizard.OPEN))
            m_util.showOpenDialog();
          else
            newPresentation();
        }
        noow.dispose();
      }
    }
    else {
      // If not autoconnecting, the display the connect dialog
      showConnectDialog();
    }
  }

  /**
   * Main method for Analyzer.
   * This method instantiates an Analyzer, passing the title and the 
   * parameter value to the constructor.
   *
   * @param args[] Pass "autoconnect" if the application should use parameters
   *               in analyzerTemplate.xml for connection information.
   *
   * @see #Analyzer
   */
  public static void main(String args[]) {
    String autoCon = args.length > 0 ? args[0] : "";
    Analyzer analyzer = new Analyzer(TITLE, autoCon);
  }

  /**
   * Overrides the setVisible method from JComponent to allow the centering of
   * the Analyzer before displaying it.
   *
   * @param visible <code>true</code> to make Analyzer visible.
   *                <code>false</code> to hide it.
   */
  public void setVisible(boolean visible) {
    // center the frame
    WindowUtils.centerWindow(this);
    super.setVisible(visible);
  }

  /**
   * Retrieves the status bar used by this Analyzer. The status bar contains
   * messages like "Connected", "Attempting to connect...", and so on.
   *
   * @return The status bar for this Analyzer.
   */
  protected StatusBar getStatusBar() {
    return m_statusBar;
  }

  /**
   * Retrieves the sidebar for this Analyzer.  The sidebar contains
   * the three Explorers: Worksheets, Saved Selections, Members.
   * 
   * @returns The sidebar for this application.
   */
   public Sidebar getSidebar() {
     return m_sidebar;
   }

  /**
   * Retrieves the Analyzer toolbar.
   * The Analyzer toolbar is a GraphToolBar that has added tools.
   *
   * @return The Analyzer toolbar.
   * 
   * @see #jbInit
   */
  public GraphToolBar getToolBar() {
    return m_toolBar;
  }

  /**
   * Retrieves the Analyzer desktop. This is the area where crosstabs and graphs
   * are displayed.
   * @return The Analyzer desktop object.
   */
  public JDesktopPane getDesktop () {
    return m_desktop;
  }

  /**
   * Handles all of the application's menu and custom toolbar events.
   * 
   * @param e Information about the action that the user performed.
   */
  public void actionPerformed(ActionEvent e) {
      /*
       * Handle toolbar and menu events
       */
       String cmd = e.getActionCommand();
        if (cmd.equalsIgnoreCase(FILE_NEW))
          newPresentation();
        else if (cmd.equalsIgnoreCase(FILE_OPEN))
          m_util.showOpenDialog();
        else if (cmd.equalsIgnoreCase(FILE_CONNECT))
          showConnectDialog();
        else if (cmd.equalsIgnoreCase(FILE_DISCONNECT))
          showDisconnectDialog();
        else if (cmd.equalsIgnoreCase(FILE_EXPORT))
          m_util.showExportDialog();
        else if (cmd.equalsIgnoreCase(FILE_PRINT))
          m_util.showPrintDialog();
        else if (cmd.equalsIgnoreCase(FILE_SAVE))
          save();
        else if (cmd.equalsIgnoreCase(FILE_SAVEAS))
          m_util.showSaveAsDialog();
        else if (cmd.equalsIgnoreCase(FILE_EXIT))
          exit();
        else if (cmd.equalsIgnoreCase(TOOLS_CB))
          m_util.runCalcBuilder();
        else if (cmd.equalsIgnoreCase(TOOLS_QB))
          m_util.runQueryBuilder();
        else if (cmd.equalsIgnoreCase(TOOLS_FORMATGRAPH))
          m_util.showGraphFormatDialog();
        else if (cmd.equalsIgnoreCase(TOOLS_GRAPHTYPE))
          m_util.showGraphTypeDialog();
        else if (cmd.equalsIgnoreCase(TILE_HORIZONTAL))
          tileWorksheets(TILE_HORIZONTAL);
        else if (cmd.equalsIgnoreCase(TILE_VERTICAL))
          tileWorksheets(TILE_VERTICAL);
        else if (cmd.equalsIgnoreCase(HELP_ABOUT))
          showAboutDialog();
        else if (cmd.equalsIgnoreCase(VIEW_GRAPH))
          setDataviewType(VIEW_GRAPH);
        else if (cmd.equalsIgnoreCase(VIEW_CROSSTAB))
          setDataviewType(VIEW_CROSSTAB);
  }

  /**
   * Initializes the user interface.  
   * This method instantiates the connection and utility objects and sets
   * them on this Analyzer.
   * Then this method:
   * <ol>
   * <li>Creates menus and menu items and adds them to a menu bar.</li>
   * <li>Creates buttons and adds them to a Graph toolbar to make
   *     the Analyzer toolbar.</li>
   * <li>Creates a status bar.</li>
   * <li>Creates the desktop as a multi-document interface window.</li>
   * <li>Enables drag-drop support.</li>
   * <li>Creates the sidebar and adds Explorers to it.</li>
   * <li>Creates a JSplitPane and adds the desktop and the sidebar to it.</li>
   * <li>Puts the toolbar, the JSplitPane, and the status bar in a border 
   *     layout manager.</li>
   * </ol>
   */
  protected void jbInit() {
    // Initialize connection object
    m_connection = new AnalyzerConnection(this);

    /* Initialize the utility object.  This class is responsible for performing
     * tasks like displaying dialogs, showing busy bar, etc
     */
    m_util = new AnalyzerUtilities(this);

    /*
     * Set up all the menus in the following order:
     * 1. Set up the menu items
     * 2. Add the menu items to the application menus
     */
    // File Menu
    m_mnuFile.setText(StringUtils.stripMnemonic(FILE));
    m_mnuFile.setMnemonic(StringUtils.getMnemonicKeyCode(FILE));
    m_mnuNew.setText(StringUtils.stripMnemonic(FILE_NEW));
    m_mnuNew.setMnemonic(StringUtils.getMnemonicKeyCode(FILE_NEW));
    m_mnuNew.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/new.gif")));
    m_mnuNew.setActionCommand(FILE_NEW);
    m_mnuNew.addActionListener(this);
    m_mnuOpen.setText(StringUtils.stripMnemonic(FILE_OPEN));
    m_mnuOpen.setMnemonic(StringUtils.getMnemonicKeyCode(FILE_OPEN));
    m_mnuOpen.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/open.gif")));
    m_mnuOpen.setActionCommand(FILE_OPEN);
    m_mnuOpen.addActionListener(this);
    m_mnuSave.setText(StringUtils.stripMnemonic(FILE_SAVE));
    m_mnuSave.setMnemonic(StringUtils.getMnemonicKeyCode(FILE_SAVE));
    m_mnuSave.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/filesave.gif")));
    m_mnuSave.setActionCommand(FILE_SAVE);
    m_mnuSave.addActionListener(this);

    m_mnuSaveAs.setText(StringUtils.stripMnemonic(FILE_SAVEAS));
    m_mnuSaveAs.setMnemonic(StringUtils.getMnemonicKeyCode(FILE_SAVEAS));
    m_mnuSaveAs.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/blank.gif")));
    m_mnuSaveAs.setActionCommand(FILE_SAVEAS);
    m_mnuSaveAs.addActionListener(this);

    m_mnuPrint.setText(StringUtils.stripMnemonic(FILE_PRINT));
    m_mnuPrint.setMnemonic(StringUtils.getMnemonicKeyCode(FILE_PRINT));
    m_mnuPrint.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/print.gif")));
    m_mnuPrint.setActionCommand(FILE_PRINT);
    m_mnuPrint.addActionListener(this);

    m_mnuExport.setText(StringUtils.stripMnemonic(FILE_EXPORT));
    m_mnuExport.setMnemonic(StringUtils.getMnemonicKeyCode(FILE_EXPORT));
    m_mnuExport.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/export.gif")));
    m_mnuExport.setActionCommand(FILE_EXPORT);
    m_mnuExport.addActionListener(this);
    m_mnuConnect.setText(StringUtils.stripMnemonic(FILE_CONNECT));
    m_mnuConnect.setMnemonic(StringUtils.getMnemonicKeyCode(FILE_CONNECT));
    m_mnuConnect.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/Connection.gif")));
    m_mnuConnect.setActionCommand(FILE_CONNECT);
    m_mnuConnect.addActionListener(this);

    m_mnuDisconnect.setText(StringUtils.stripMnemonic(FILE_DISCONNECT));
    m_mnuDisconnect.setMnemonic(StringUtils.getMnemonicKeyCode(FILE_DISCONNECT));
    m_mnuDisconnect.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/blank.gif")));
    m_mnuDisconnect.setActionCommand(FILE_DISCONNECT);
    m_mnuDisconnect.addActionListener(this);
    m_mnuExit.setText(StringUtils.stripMnemonic(FILE_EXIT));
    m_mnuExit.setMnemonic(StringUtils.getMnemonicKeyCode(FILE_EXIT));
    m_mnuExit.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/blank.gif")));
    m_mnuExit.setActionCommand(FILE_EXIT);
    m_mnuExit.addActionListener(this);

    // Tools Menu
    m_mnuTools.setText(StringUtils.stripMnemonic(TOOLS));
    m_mnuTools.setMnemonic(StringUtils.getMnemonicKeyCode(TOOLS));
    m_mnuQB.setText(StringUtils.stripMnemonic(TOOLS_QB));
    m_mnuQB.setMnemonic(StringUtils.getMnemonicKeyCode(TOOLS_QB));
    m_mnuQB.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/query.gif")));
    m_mnuQB.setActionCommand(TOOLS_QB);
    m_mnuQB.addActionListener(this);

    m_mnuCB.setText(StringUtils.stripMnemonic(TOOLS_CB));
    m_mnuCB.setMnemonic(StringUtils.getMnemonicKeyCode(TOOLS_CB));
    m_mnuCB.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/calc.gif")));
    m_mnuCB.setActionCommand(TOOLS_CB);
    m_mnuCB.addActionListener(this);

    m_mnuFmtGraph.setText(StringUtils.stripMnemonic(TOOLS_FORMATGRAPH));
    m_mnuFmtGraph.setMnemonic(StringUtils.getMnemonicKeyCode(TOOLS_FORMATGRAPH));
    m_mnuFmtGraph.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/bi_gCust.gif")));
    m_mnuFmtGraph.setActionCommand(TOOLS_FORMATGRAPH);
    m_mnuFmtGraph.addActionListener(this);

    m_mnuGraphType.setText(StringUtils.stripMnemonic(TOOLS_GRAPHTYPE));
    m_mnuGraphType.setMnemonic(StringUtils.getMnemonicKeyCode(TOOLS_GRAPHTYPE));
    m_mnuGraphType.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/graphtype_style.gif")));
    m_mnuGraphType.setActionCommand(TOOLS_GRAPHTYPE);
    m_mnuGraphType.addActionListener(this);

    // View Menu
    m_mnuView.setText(StringUtils.stripMnemonic(VIEW));
    m_mnuView.setMnemonic(StringUtils.getMnemonicKeyCode(VIEW));
    ButtonGroup viewMenuGroup = new ButtonGroup();
    viewMenuGroup.add(m_mnuGraph);
    viewMenuGroup.add(m_mnuCrosstab);
    m_mnuGraph.setText(StringUtils.stripMnemonic(VIEW_GRAPH));
    m_mnuGraph.setMnemonic(StringUtils.getMnemonicKeyCode(VIEW_GRAPH));
    m_mnuGraph.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/graph_db.gif")));
    m_mnuGraph.setActionCommand(VIEW_GRAPH);
    m_mnuGraph.addActionListener(this);
    m_mnuCrosstab.setText(StringUtils.stripMnemonic(VIEW_CROSSTAB));
    m_mnuCrosstab.setMnemonic(StringUtils.getMnemonicKeyCode(VIEW_CROSSTAB));
    m_mnuCrosstab.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/crosstab_db.gif")));
    m_mnuCrosstab.setActionCommand(VIEW_CROSSTAB);
    m_mnuCrosstab.addActionListener(this);

    // Window Menu: Tile, window list
    m_mnuWindow.setText(StringUtils.stripMnemonic(WINDOW));
    m_mnuWindow.setMnemonic(StringUtils.getMnemonicKeyCode(WINDOW));
    m_mnuHorizontal.setText(StringUtils.stripMnemonic(TILE_HORIZONTAL));
    m_mnuHorizontal.setMnemonic(StringUtils.getMnemonicKeyCode(TILE_HORIZONTAL));
    m_mnuHorizontal.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/tilehoriz.gif")));
    m_mnuHorizontal.setActionCommand(TILE_HORIZONTAL);
    m_mnuHorizontal.addActionListener(this);

    m_mnuVertical.setText(StringUtils.stripMnemonic(TILE_VERTICAL));
    m_mnuVertical.setMnemonic(StringUtils.getMnemonicKeyCode(TILE_VERTICAL));
    m_mnuVertical.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/tilevertic.gif")));
    m_mnuVertical.setActionCommand(TILE_VERTICAL);
    m_mnuVertical.addActionListener(this);

    // Help Menu
    m_mnuHelp.setText(StringUtils.stripMnemonic(HELP));
    m_mnuHelp.setMnemonic(StringUtils.getMnemonicKeyCode(HELP));
    m_aboutMenu.setText(StringUtils.stripMnemonic(HELP_ABOUT));
    m_aboutMenu.setMnemonic(StringUtils.getMnemonicKeyCode(HELP_ABOUT));
    m_aboutMenu.setIcon(new ImageIcon(
                               Analyzer.class.getResource("images/about.gif")));
    m_aboutMenu.setActionCommand(HELP_ABOUT);
    m_aboutMenu.addActionListener(this);

    // Add the menu items to the menus and the menus to the menubar
    m_menubar.add(m_mnuFile);
    m_menubar.add(m_mnuTools);
    m_menubar.add(m_mnuView);
    m_menubar.add(m_mnuWindow);
    m_menubar.add(m_mnuHelp);
    m_mnuFile.add(m_mnuNew);
    m_mnuFile.add(m_mnuOpen);
    m_mnuFile.addSeparator();
    m_mnuFile.add(m_mnuSave);
    m_mnuFile.add(m_mnuSaveAs);
    m_mnuFile.addSeparator();
    m_mnuFile.add(m_mnuPrint);
    m_mnuFile.addSeparator();
    m_mnuFile.add(m_mnuExport);
    m_mnuFile.addSeparator();
    m_mnuFile.add(m_mnuConnect);
    m_mnuFile.add(m_mnuDisconnect);
    m_mnuFile.addSeparator();
    m_mnuFile.add(m_mnuExit);
    m_mnuTools.add(m_mnuQB);
    m_mnuTools.add(m_mnuCB);
    m_mnuTools.addSeparator();
    m_mnuTools.add(m_mnuGraphType);
    m_mnuTools.add(m_mnuFmtGraph);
    m_mnuView.add(m_mnuGraph);
    m_mnuView.add(m_mnuCrosstab);
    m_mnuWindow.add(m_mnuHorizontal);
    m_mnuWindow.add(m_mnuVertical);
    m_mnuWindow.addSeparator();
    m_mnuHelp.add(m_aboutMenu);

    /*
     * Update the toolbar with a few features
     * 1. New
     * 2. Open
     * 3. Save
     * 4. Edit Query
     * 5. New Calculation
     * 6. Change view to Graph/Crosstab
     */

    btnNew = new JButton(new ImageIcon(
                               Analyzer.class.getResource("images/toolbar/ssheet.gif")));
    btnNew.setActionCommand(FILE_NEW);
    btnNew.addActionListener(this);
    btnNew.setEnabled(false);
    btnNew.setToolTipText(StringUtils.stripMnemonic(FILE_NEW));
    btnOpen = new JButton(new ImageIcon(
                               Analyzer.class.getResource("images/toolbar/sopen.gif")));
    btnOpen.setActionCommand(FILE_OPEN);
    btnOpen.addActionListener(this);
    btnOpen.setEnabled(false);
    btnOpen.setToolTipText(StringUtils.stripMnemonic(FILE_OPEN));
    btnSave = new JButton(new ImageIcon(
                               Analyzer.class.getResource("images/toolbar/ssave.gif")));
    btnSave.setActionCommand(FILE_SAVE);
    btnSave.addActionListener(this);
    btnSave.setEnabled(false);
    btnSave.setToolTipText(StringUtils.stripMnemonic(FILE_SAVE));

    // Create Graph/Crosstab toggle buttons
    btnGraph = new JToggleButton(new ImageIcon(
                               Analyzer.class.getResource("images/graph_db.gif")));
    btnGraph.setActionCommand(VIEW_GRAPH);
    btnGraph.addActionListener(this);
    btnGraph.setEnabled(false);
    btnGraph.setToolTipText(StringUtils.stripMnemonic(VIEW_GRAPH));
    btnCrosstab = new JToggleButton(new ImageIcon(
                               Analyzer.class.getResource("images/crosstab_db.gif")));
    btnCrosstab.setActionCommand(VIEW_CROSSTAB);
    btnCrosstab.addActionListener(this);
    btnCrosstab.setEnabled(false);
    btnCrosstab.setToolTipText(StringUtils.stripMnemonic(VIEW_CROSSTAB));

    ButtonGroup toolbarGroup = new ButtonGroup();
    toolbarGroup.add(btnCrosstab);
    toolbarGroup.add(btnGraph);

    // Create Calcbuilder and QueryBuilder buttons
    btnCB = new JButton(new ImageIcon(
                               Analyzer.class.getResource("images/toolbar/scalc.gif")));

    btnCB.setActionCommand(TOOLS_CB);
    btnCB.addActionListener(this);
    btnCB.setEnabled(false);
    btnCB.setToolTipText(StringUtils.stripMnemonic(TOOLS_CB));
    btnQB = new JButton(new ImageIcon(
                               Analyzer.class.getResource("images/toolbar/scond.gif")));
    btnQB.setActionCommand(TOOLS_QB);
    btnQB.addActionListener(this);
    btnQB.setEnabled(false);
    btnQB.setToolTipText(StringUtils.stripMnemonic(TOOLS_QB));

    // Use BI Beans DecimalTool and NumberTypeTool
    DecimalTool btnDecimal = new DecimalTool();
    NumberTypeTool btnNumType = new NumberTypeTool();

    // Add the buttons to the toolbar
    JToolBar toolBar = new JToolBar();
    toolBar.add(btnNew);
    toolBar.add(btnOpen);
    toolBar.add(btnSave);
    toolBar.addSeparator();
    toolBar.add(btnGraph);
    toolBar.add(btnCrosstab);
    toolBar.addSeparator();
    toolBar.add(btnQB);
    toolBar.add(btnCB);
    toolBar.addSeparator();
    toolBar.setBorderPainted(false);
    m_toolBar.add(toolBar, 0);
    m_toolBar.addSeparator();
    m_toolBar.add(btnDecimal);
    m_toolBar.add(btnNumType);

    // Add a ToolbarFormatListener which will track changes to the toolbar.
    // PropertyChangeEvents are used to track changes
    m_toolbarFormatListener = new ToolbarFormatListener(this);
    m_toolBar.addPropertyChangeListener(m_toolbarFormatListener);
    btnDecimal.addPropertyChangeListener(m_toolbarFormatListener);
    btnNumType.addPropertyChangeListener(m_toolbarFormatListener);

    /*
     * Create the status bar
     */
    JPanel statusBar = new JPanel(new BorderLayout());
    m_statusBar = new StatusBar();
    m_statusBar.add(NOT_CONNECTED);
    statusBar.add(m_statusBar, BorderLayout.CENTER);

    // Set up MDI
    m_desktop = new JDesktopPane();
    m_desktop.setBorder(OracleBorderFactory.getLoweredBevelBorder());
    m_desktop.putClientProperty("JDesktopPane.dragMode", "outline");

    /*
     * Make the desktop a drop target for items in the Catalog Explorer.
     * An AnalyzerDropTarget (derived from DropTarget) makes it a little easier
     * for the application to understand drag/drop events
     */
    AnalyzerDropTarget dropTarget = new AnalyzerDropTarget(m_desktop, // component
        DnDConstants.ACTION_COPY_OR_MOVE, // actions
        this); // DropTargetListener
    dropTarget.setAnalyzerTarget(AnalyzerDropTarget.DESKTOP);

    /*
     * Create sidebar
     */
    m_sidebar = new Sidebar();

    // worksheet explorer - only show objects that have a GRAPH or CROSSTAB attribute
    BasicAttribute basicAttribute = new BasicAttribute(PSRConstants.Attributes.OBJECT_TYPE, PSRConstants.CROSSTAB);
    basicAttribute.add(PSRConstants.GRAPH);
    BasicAttributes basicAttributes = new BasicAttributes();
    basicAttributes.put(basicAttribute);    
    
    m_worksheetExplorer = new CatalogExplorer();
    m_worksheetExplorer.setBasicAttributes(basicAttributes);
    
    m_sidebar.addExplorer(m_worksheetExplorer, WORKSHEET_EXPLORER);

    // Favorites (or saved selection) Explorer
    m_favoritesExplorer = new FavoritesExplorer();
    m_sidebar.addExplorer(m_favoritesExplorer, FAVORITES_EXPLORER);

    // Dimension member explorer
    m_dimensionExplorer = new DimensionExplorer((Frame) this);
    m_sidebar.addExplorer(m_dimensionExplorer, DIMENSION_EXPLORER);

    // Add listeners to the sidebar Explorers.
    m_catalogListener = new MouseAdapter() {
       public void mousePressed(MouseEvent e) {
           // When user double clicks on a presentation - open it.
           JTree tree = m_worksheetExplorer.getJTree();
           int selRow = tree.getRowForLocation(e.getX(), e.getY());
           TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
           if((selRow != -1) && (e.getClickCount() == 2)) {
              CatalogTreeNode node = (CatalogTreeNode) selPath.getLastPathComponent();
              // open if leaf node (do not "open" folder)
              if (node.isLeaf()) {
                // Get the name of the worksheet and open it to fill the desktop
                String strName = node.getFullPathName();
                m_util.openView(strName, false, 0, 0,
                                m_desktop.getWidth(), m_desktop.getHeight());
              }
            }
       }
     };

    m_worksheetExplorer.getJTree().addMouseListener(m_catalogListener);

    /*
     * Create splitter for main window.  On the left side will be the Explorers -
     * on the right the desktop area
     */
    m_splitpane = new JSplitPane();
    m_splitpane.setOneTouchExpandable(true);
    m_splitpane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
    m_splitpane.setRightComponent(m_desktop);
    m_splitpane.setLeftComponent(m_sidebar);
    m_splitpane.setDividerLocation(200);

    // put all of these into the frame
    setJMenuBar(m_menubar);
    getContentPane().setLayout(new BorderLayout());
    getContentPane().add(m_toolBar, BorderLayout.NORTH);
    getContentPane().add(m_splitpane, BorderLayout.CENTER);
    getContentPane().add(statusBar, BorderLayout.SOUTH);


    // add a listener to listen for the window closing event
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        exit();
      }
    });
  }

  /* --------------------------------
   * Process Menu and Toolbar actions
   * --------------------------------
   */

  /**
   * Sets the view type for the active worksheet to a Graph or a Crosstab.
   * 
   * @param viewType A contant that identifies the view type. Valid constants
   *                are VIEW_GRAPH and VIEW_CROSSTAB.
   *                
   * @see #VIEW_GRAPH
   * @see #VIEW_CROSSTAB
   */
  // Set the view type to a crosstab or a graph
  private void setDataviewType(String viewType) {
    // The Worksheet contains the method that sets the view type
    getActiveWorksheet().setDataviewType(viewType);
    // The worksheet is now dirty since its format has changes
    getActiveWorksheet().setDirty(true);
    enableMenus();
  }

  /**
   * Displays the About dialog.
   * This method is called when a user chooses the About item from the
   * Help menu.
   * 
   * @see AnalyzerAboutDialog
   */
  private void showAboutDialog() {
    AnalyzerAboutDialog about = new AnalyzerAboutDialog(this, TITLE, true);
    about.setSize(500,500);
    WindowUtils.centerWindow(about);
    about.show();
  }

  /**
   * Displays a connection dialog box that asks the user for connection
   * information.
   * This method then calls the initializeUI method to initialize explorers
   * and menus.
   * 
   * @see #initializeUI
   * @see AnalyzerConnection#showConnectDialog
   */
  private void showConnectDialog() {
    m_connection.showConnectDialog(this);
    initializeUI();
  }

  /**
   * Initializes the Explorers and the menu.
   * This method gets the MetadataManager and the root folder from the
   * connection and sets them on the Explorers that need them.
   * It then calls the enableMenus method to update the menus appropriately.
   * 
   * @see #enableMenus
   */
  public void initializeUI () {
    // If connection was successful, populate the catalog explorer
    if (m_connection.isConnected()) {
      try {
        m_worksheetExplorer.setMetadataManager(m_connection.getMetadataManager());
        m_worksheetExplorer.setMDRoot(m_connection.getRootFolder());

        m_favoritesExplorer.setMetadataManager(m_connection.getMetadataManager());
        m_favoritesExplorer.setMDRoot(m_connection.getRootFolder());

        m_dimensionExplorer.setMetadataManager(m_connection.getMetadataManager());

      }
      catch (Throwable t) {
      
        System.out.println("Error setting root folder on Document Explorer.");
        t.printStackTrace();
      }
    }
    enableMenus();
  }

  /**
   * Displays a confirmation dialog asking if the user wants to disconnect.
   * This method is called when the user chooses the Disconnect item from
   * the File menu.
   * 
   * @see AnalyzerConnection#showDisconnectDialog
   */
  private void showDisconnectDialog() {
    m_connection.showDisconnectDialog(this);
  }

  /**
   * Updates the user interface after the user disconnects.
   * This method removes all worksheets. It sets the query in the Favorites
   * Explorer to null, and it sets the MetadataManager of the Catalog
   * Explorer to null.
   * 
   * @see #removeAllWorksheets
   * @see FavoritesExplorer#setQuery
   * @see CatalogExplorer#setMetadataManager
   */
  public void disconnectCleanUp () {
    removeAllWorksheets();
    m_favoritesExplorer.setQuery(null);
    m_worksheetExplorer.setMetadataManager(null);


  }

  /**
   *  Runs the New Presentation wizard and creates a worksheet for the
   *  presentation.
   *  This method is called when a user chooses New from the File menu.
   *  
   *  @see NewPresentationWizard
   *  @see #addWorksheet
   */
  private void newPresentation() {
      // Create a presentation
      NewPresentationWizard npw = new NewPresentationWizard(this);
      npw.setQueryManager(m_connection.getQueryManager());

      /*
       *  The "run" method on the NewPresentationWizard returns true if a view
       *  (graph or crosstab) is fully specified, false if user cancelled...
       *  If all is okay, create a new view worksheet
       */
      if (npw.run()) {
        /*
         *  Create the worksheet
         */
        Dataview dv = npw.getDataview();
        addWorksheet(UNTITLED, dv, true, 0, 0, 400, 400);
      }
  }

  /**
   * Cleans up and exits.
   * This method is called when the user selects Exit from the File menu 
   * or when the user closes the main window.
   * 
   * @see #removeAllWorksheets
   */
  private void exit() {
    // Close all of the worksheets
    removeAllWorksheets();

    // disconnect if we are connected when exit
    if (m_connection.isConnected()) {
      m_connection.disconnect();
    }
    dispose();
    System.exit(0);
  }

  /**
   * Enables menus and toolbar buttons, based on the current state of the 
   * application.
   */
  public void enableMenus() {
    if (m_connection.isConnected()) {
      // disable the connect menu item and button, enable the disconnect menu
      // item and button
      m_mnuConnect.setEnabled(false);
      m_mnuDisconnect.setEnabled(true);
      m_mnuNew.setEnabled(true);
      m_mnuOpen.setEnabled(true);
      btnNew.setEnabled(true);
      btnOpen.setEnabled(true);

      // update the status
      setStatusBarMessage(CONNECTED);

    }
    else {
      m_mnuConnect.setEnabled(true);
      m_mnuDisconnect.setEnabled(false);
      m_mnuNew.setEnabled(false);
      m_mnuOpen.setEnabled(false);
      btnNew.setEnabled(false);
      btnOpen.setEnabled(false);

      // update the status
      setStatusBarMessage(NOT_CONNECTED);

    }

    if (getActiveWorksheet() != null) {
      m_mnuExport.setEnabled(true);
      m_mnuPrint.setEnabled(true);
      m_mnuSave.setEnabled(true);
      m_mnuSaveAs.setEnabled(true);
      m_mnuCB.setEnabled(true);
      m_mnuQB.setEnabled(true);
      m_mnuGraph.setEnabled(true);
      m_mnuCrosstab.setEnabled(true);
      btnGraph.setEnabled(true);
      btnCrosstab.setEnabled(true);
      btnSave.setEnabled(true);
      btnCB.setEnabled(true);
      btnQB.setEnabled(true);

      // Set the default state for the view type radio buttons and enable format menu
      if (getActiveWorksheet().getActiveDataview() instanceof oracle.dss.graph.Graph) {
        m_mnuGraph.setSelected(true);
        btnGraph.setSelected(true);
        m_mnuFmtGraph.setEnabled(true);
        m_mnuGraphType.setEnabled(true);
      }
      else {
        m_mnuCrosstab.setSelected(true);
        btnCrosstab.setSelected(true);
        m_mnuFmtGraph.setEnabled(false);
        m_mnuGraphType.setEnabled(false);
      }

      // Update the toolbar
      m_toolBar.setDataView(getActiveWorksheet().getActiveDataview());
    }
    else {
      m_mnuExport.setEnabled(false);
      m_mnuPrint.setEnabled(false);
      m_mnuSave.setEnabled(false);
      m_mnuSaveAs.setEnabled(false);
      m_mnuCB.setEnabled(false);
      m_mnuQB.setEnabled(false);
      m_mnuFmtGraph.setEnabled(false);
      m_mnuGraphType.setEnabled(false);
      m_mnuGraph.setEnabled(false);
      m_mnuCrosstab.setEnabled(false);
      btnGraph.setEnabled(false);
      btnCrosstab.setEnabled(false);
      btnSave.setEnabled(false);
      btnCB.setEnabled(false);
      btnQB.setEnabled(false);

      // Update the toolbar
      m_toolBar.setDataView(null);

    }

    if (m_desktop.getAllFrames().length > 0) {
      m_mnuHorizontal.setEnabled(true);
      m_mnuVertical.setEnabled(true);
    }
    else {
      m_mnuHorizontal.setEnabled(false);
      m_mnuVertical.setEnabled(false);
    }

  }

  /**
   * Updates the list of open windows in the Window menu.
   */
  public void updateListOfWorksheets() {
    /*
     *  The first 3 components are:
     *  1. Tile Horizontal
     *  2. Tile Vertical
     *  3. Separator
     *  After the separator, add the menus
     */
     // Remove the items
     int numItems = m_mnuWindow.getMenuComponentCount();
     for (int i = 3; i < numItems; i++)  {
        // Always remove the first worksheet in the list
        m_mnuWindow.remove(3);
     }

    // Add the items
     int numWorksheets = m_desktop.getAllFrames().length;
     JInternalFrame worksheets[] = m_desktop.getAllFrames();

     for (int i = 0; i < numWorksheets; i++)  {
        String menuNum = "&" + (i+1);
        String menuText = menuNum + " - " + worksheets[i].getTitle();
        AnalyzerMenuItem menuItem = new AnalyzerMenuItem();
        menuItem.setText(StringUtils.stripMnemonic(menuText));
        menuItem.setMnemonic(StringUtils.getMnemonicKeyCode(menuNum));
        menuItem.setFont(m_mnuHorizontal.getFont());
        menuItem.setWorksheet((Worksheet)worksheets[i]);

        // Add a listener to the menuItem that makes the selected window active
        menuItem.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
              try {
                ((AnalyzerMenuItem) e.getSource()).getWorksheet().setSelected(true);
              }
              catch (Exception ex) {
                System.out.println(ex.getMessage());
              }
            }
          }
        );
        m_mnuWindow.add(menuItem);
     }


  }

  /**
   * Adds a worksheet to the desktop.
   * This method also updates the list of open worksheets, and it updates
   * the list of dimensions in the Dimension Explorer.
   * 
   * This method is called when the New Presentation wizard runs successfully.
   * 
   * @param name Fully qualified name of the data presentation. This becomes
   *             the title of the worksheet.
   * @param dv The <code>Dataview</code> object that will be added to the worksheet.
   * @param isDirty <code>true</code> if the <code>Dataview</code> is dirty
   *         (needs to be saved), 
   *         <code>false</code> if no changes have been made since the last 
   *         save.
   *         A new <code>Dataview</code> from the Presentation wizard is dirty.
   * @param x The horizontal position for the view in the desktop.
   * @param y The vertical position for the view in the desktop.
   * @param width The width of the view.
   * @param height The height of the view.
   * 
   * @see #newPresentation
   * @see Worksheet
   */
  public void addWorksheet(String name, Dataview dv, boolean isDirty,
                      int x, int y, int width, int height)  {
    // Create the worksheet
    Worksheet worksheet = new Worksheet(this);

    // add a listener to the worksheet
    worksheet.addInternalFrameListener(this);
    worksheet.reshape(x,y,width,height);

    // Ensure the view is drillable
    dv.setDrillingEnabled(true);
    
    // Add the dataview to the worksheet
    worksheet.addDataview(dv);
    worksheet.setDirty(isDirty);
    worksheet.setTitle(name);
    worksheet.setVisible(true); //necessary as of 1.3; OK to use before

    // Add the worksheet to the desktop
    m_desktop.add(worksheet);
    try {
          worksheet.setSelected(true);
          updateListOfWorksheets();
    }
    catch (java.beans.PropertyVetoException e) {}

    /*
     * The dimension explorer tracks all the dimensions used by the open worksheets
     * Add this worksheet's dimensions to the list of dimensions that are being used
     */
    m_dimensionExplorer.addDimensions((QueryClient) dv.getDataSource());
  }

  /**
   * Removes a worksheet from the desktop.  
   * This method also does the following clean-up tasks:
   * <ol>
   * <li>Updates the Explorers</li>
   * <li>Updates menus</li>
   * </ol>
   * 
   * @param Worksheet The <code>Worksheet</code> object to remove.
   */
  public void removeWorksheet(Worksheet worksheet) {
    // remove dimensions from the Dimension Explorer
    m_dimensionExplorer.removeDimensions((QueryClient) worksheet.getActiveDataview().getDataSource());

    // Clean-up the worksheet
    worksheet.removeInternalFrameListener(this);
    worksheet.cleanUp();
    worksheet.dispose();

    // Check for other worksheets.  If this is the last one, then set the active view to null
    // setActiveWorksheet is normally called when a worksheet is activated.  Since no worksheet will be activated,
    // we're calling it here

    if (m_desktop.getAllFrames().length == 0) {
      setActiveWorksheet(null);
    }

    // Update the menus
    updateListOfWorksheets();
    enableMenus();

    // Update the UI
    invalidate();
    validate();
    repaint();
  }

  /**
   * Removes all worksheets from the desktop.  
   * This method is called when the user disconnects from the database.
   */
  public void removeAllWorksheets() {

    JInternalFrame[] worksheets = m_desktop.getAllFrames();

    for (int i = 0; i < worksheets.length; i++)  {
      worksheets[i].doDefaultCloseAction();

      try {
        worksheets[i].setClosed(true);
      }
      catch (Exception e) {
        System.out.println("Unable to close worksheet.");
      }
    }
  }

  /**
   * Saves the active presentation.
   * 
   * @see AnalyzerUtilities#showSaveAsDialog
   * @see AnalyzerUtilities#saveView
   */
  private void save () {
    // Check if there is an Active dataview
    if (getActiveWorksheet().getActiveDataview() == null) {
      String strMsg = "Cannot save because there is no active view.";

      m_util.showErrorMessage(strMsg, null);
      return;

    }

    // if we have a path then we had opened a view to begin with or it was saved previously
    // otherwise we delegate to the Save As method
    if (getActiveWorksheet().getActiveDataviewPath() == null)
      m_util.showSaveAsDialog();
    else
      m_util.saveView(getActiveWorksheet().getActiveDataviewPath(), getActiveWorksheet().getActiveDataview());
  }

  /**
   * Returns the Worksheet object that is currently in focus.
   */
  public Worksheet getActiveWorksheet() {
    return m_worksheet;
  }

  /**
   * Sets a worksheet as the active worksheet.
   * This method sets the Query from the worksheet's view on 
   * the FavoritesExplorer and the DimensionExplorer, so the Explorers
   * act upon the right query.
   * This method also updates menus and toolbars.
   *
   * @param worksheet The worksheet object to make active.
   * 
   * @see #enableMenus
   * @see FavoritesExplorer
   * @see DimensionExplorer
   */
  public void setActiveWorksheet(Worksheet worksheet) {
    m_worksheet = worksheet;

    // If there are no worksheets left - turn off toolbar and favorites explorer
    if (worksheet == null) {
      // Update the Favorites Explorer
      m_favoritesExplorer.setQuery(null);
    }
    else {     // There are worksheets left
      Dataview dv = worksheet.getActiveDataview();

      // Update the Explorers
      m_favoritesExplorer.setQuery((QueryClient) dv.getDataSource());
      m_dimensionExplorer.setQuery((QueryClient) dv.getDataSource());
    }

    // Update the menus
    enableMenus();
  }

  /**
   * Sets the message that the status bar displays.
   * The status bar is located at the bottom of the application frame.
   * 
   * @param message The message to display in the status bar.
   */
  public void setStatusBarMessage(String message) {
    m_statusBar.remove(0);
    m_statusBar.add(message);
  }

  /**
   * Returns the version number of this application.
   * @return Version number (e.g. 1.0.4).
   */
  public String getVersion() {
    return VERSION;
  }
  /**
   * Returns the Analyzer connection object for the current connection.
   * @return The connection object for this Analyzer.
   */
  public AnalyzerConnection getConnection() {
    return m_connection;
  }

  /**
   * Tiles the windows horizontally or vertically in the desktop.
   * @param tile The orientation for tiling.  Valid values are 
   *             Analyzer.TILE_HORIZONTAL or Analyzer.TILE_VERTICAL.
   *           
   * @see #TILE_HORIZONTAL
   * @see #TILE_VERTICAL
   */
  private void tileWorksheets(String tile) {

    JInternalFrame[] worksheets = m_desktop.getAllFrames();
    int numPages = worksheets.length;
    int desktopHeight = m_desktop.getHeight();
    int desktopWidth = m_desktop.getWidth();
    int pageWidth = 0;
    int pageHeight = 0;
    int incWidth = 0;
    int incHeight = 0;

    if (tile == TILE_HORIZONTAL) {
      /*
       * Width of page will be the width of the desktop.
       * Height of page will depend on the number of worksheets
       */
      pageWidth = desktopWidth;
      pageHeight = desktopHeight/numPages;
      incHeight = pageHeight;
      incWidth = 0;
    }
    else {
      /*
       * Width of page will depend on the number of worksheets
       * Height of page will be the height of the desktop
       */
      pageWidth = desktopWidth/numPages;
      pageHeight = desktopHeight;
      incHeight = 0;
      incWidth = pageWidth;
    }

    // Resize the worksheets based on the calculations from above
    for (int i = 0; i < numPages; i++)  {
      worksheets[i].setBounds(i*incWidth, i*incHeight, pageWidth, pageHeight);
    }

    invalidate();
    validate();
    repaint();
  }

  /**
   * Drag/drop support for the application.  
   * This method interrogates the DropTargetDropEvent and pulls out key 
   * information.
   * The drop methods call this method.
   * 
   * @param DropTargetDropEvent The DropTargetDropEvent that is being interrogated
   * @param typeOrObject The type of information to return.
   *                    "TYPE" retrieves the type of Explorer the object is
   *                      being dragged from.
   *                    "OBJECT" retrieves the the actual object that is being 
   *                    dragged and dropped.
   *                    
   * @return The name of the item being dragged and dropped.
   */
  public String getDragSourceData (DropTargetDropEvent dtde, String typeOrObject) {
    /*
     * The stringFlavor contains the information that is being dragged/dropped.
     * This information is set in the CatalogExplorer, FavoriteExplorer or MemberExplorer
     */
    String strName = null;
    try {
      DataFlavor stringFlavor = DataFlavor.stringFlavor;

      Transferable tr = dtde.getTransferable();

      // The StringFlavor contains the list name of the favorite or worksheet
      // The string looks like this:  "FAVORITE:/My Favorite/Top 5 Products"
      if (dtde.isDataFlavorSupported(stringFlavor)) {
        strName = (String)tr.getTransferData(stringFlavor);

        if (typeOrObject.equalsIgnoreCase("TYPE"))
          return strName.substring(0, strName.indexOf(":"));
        else if (typeOrObject.equalsIgnoreCase("OBJECT"))
          return strName.substring(strName.indexOf(":")+1);
      }
      else return null;
    }
    catch (Exception ex) {
      return null;
    }

    return null;
  }

  /**
   * Null implementation for DropTargetListener.
   */
  public void dragEnter(DropTargetDragEvent dtde) {}
  /**
   * Null implementation for DropTargetListener.
   */
  public void dragOver(DropTargetDragEvent dtde) {}
  /**
   * Null implementation for DropTargetListener.
   */
  public void dropActionChanged(DropTargetDragEvent dtde) {}
  /**
   * Null implementation for DropTargetListener.
   */
  public void dragExit(DropTargetEvent dte) {}


  /**
   * Examines the drag operation and changes the cursor.  
   * If the object being dragged is above an invalid drop target, the cursor 
   * changes.
   * <p>
   * Favorites and Dimension Members can be dropped on a dataview.
   * Worksheets can be dropped on the desktop.
   * 
   * @param dtde Information about the drag-drop operation.
   */
  public void drop1(DropTargetDropEvent dtde) {
    try {
      String sourceExplorer = getDragSourceData(dtde, "TYPE");
      String sourceObject = getDragSourceData(dtde, "OBJECT");

      if (sourceExplorer == null || sourceObject == null) {
        dtde.rejectDrop();
        return;
      }

      /*
       * An AnalyzerDropTarget is a specialized drop target that includes attributes
       * that make it easier to identify.  For example, there is an
       * attribute identifying the dataview that is associated with the drop target.  A dataview
       * (Graph, Crosstab) has multiple drop targets (e.g. row header, col header, etc.).
       * The AnalyzerDropTarget simplifies the determination of the dataview associated
       * with the drop target
       */
      AnalyzerDropTarget dropTarget = (AnalyzerDropTarget) dtde.getDropTargetContext().getDropTarget();

      /*
       * Dropping an object on a dataview
       */
      if (dropTarget.getAnalyzerTarget() == AnalyzerDropTarget.DATAVIEW) {
        // Only allow dropping a favorite or member on a dataview
        if (! (sourceExplorer.equalsIgnoreCase("FAVORITES") ||
            sourceExplorer.equalsIgnoreCase("MEMBER"))) {
            dtde.rejectDrop();
            return;
        }

        dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
        dtde.dropComplete(true);
        /*
         * The AnalyzerDropTarget has the following attributes:  dataview, worksheet where dataview lives
         * The worksheet has a Title attribute which stores the path to the dataview (and worksheet)
         * Update the dataview's query with the saved selection or list of dimension members
         */
        Dataview dv = dropTarget.getDataview();
        String path = dropTarget.getWorksheet().getTitle();
        Worksheet worksheet = dropTarget.getWorksheet();

        //Set active dataview here
        worksheet.setActiveDataview(dv);
        worksheet.setActiveDataviewPath(path);
        worksheet.setSelected(true);

        // Check if the object being dropped is a member selection or a favorite
        if (sourceExplorer.equalsIgnoreCase("MEMBER"))
          m_dimensionExplorer.applyDimListSelection();
        else if (sourceExplorer.equalsIgnoreCase("FAVORITES"))
          m_favoritesExplorer.applySelection(sourceObject);
      }
      /*
       * Dropping a worksheet onto the desktop.  Open the worksheet
       */
      else {
        // Only allow a Worksheet to be dropped on the desktop
        if (! sourceExplorer.equalsIgnoreCase("WORKSHEET")) {
          dtde.rejectDrop();
          return;
        }
        dtde.dropComplete(true);
        Point point = dtde.getLocation();

        // Set the size of the view to extend to the full height and width that's available
        double width = m_desktop.getWidth() - point.getX();
        double height = m_desktop.getHeight() - point.getY();
        m_util.openView(sourceObject, false, new Double(point.getX()).intValue(),
                  new Double(point.getY()).intValue(),
                  new Double(width).intValue(), new Double(height).intValue());
      }
    }
    catch (Exception ex) {
      System.out.println("Drag and drop operation unsuccessful.");
    }
  }

  /**
   * Examines the drag operation and changes the cursor.  
   * If the object being dragged is above an invalid drop target, the cursor 
   * changes.
   * <p>
   * Favorites and Dimension Members can be dropped on a dataview.
   * Worksheets can be dropped on the desktop.
   * 
   * @param dtde Information about the drag-drop operation.
   */
  public void drop(DropTargetDropEvent dtde) {
    try {
      String sourceExplorer = getDragSourceData(dtde, "TYPE");
      String sourceObject = getDragSourceData(dtde, "OBJECT");

      if (sourceExplorer == null || sourceObject == null) {
        dtde.rejectDrop();
        return;
      }

      /*
       * An AnalyzerDropTarget is a specialized drop target that includes attributes
       * that make it easier to identify.  For example, there is an
       * attribute identifying the dataview that is associated with the drop target.  A dataview
       * (Graph, Crosstab) has multiple drop targets (e.g. row header, col header, etc.).
       * The AnalyzerDropTarget simplifies the determination of the dataview associated
       * with the drop target
       */
      AnalyzerDropTarget dropTarget = (AnalyzerDropTarget) dtde.getDropTargetContext().getDropTarget();

      /*
       * Allow the dropping of a worksheet on any type of object in the desktop.  It will
       * simply open up the worksheet
       */
      if (sourceExplorer.equalsIgnoreCase("WORKSHEET")) {
        dtde.dropComplete(true);
        Point point = dtde.getLocation();
        int width, height, top, left;

        /*
         * Set the size of the view to extend to the full height and width that's available
         * The top left of the worksheet will depend on where it's dropped.  If it's dropped
         * on a dataview, create a cascading view effect.  If it's dropped on the desktop,
         * Drop it exactly where the user specified
         */
        if (dropTarget.getAnalyzerTarget() == AnalyzerDropTarget.DATAVIEW) {
          top = new Double(dropTarget.getWorksheet().getLocation().getY()).intValue() + 20;
          left = new Double(dropTarget.getWorksheet().getLocation().getX()).intValue() + 20;
        }
        else {
          left = new Double(point.getX()).intValue();
          top = new Double(point.getY()).intValue();
        }

        // Height and width expand to the size of the desktop
        width = m_desktop.getWidth() - left;
        height = m_desktop.getHeight() - top;

        // open the view
        m_util.openView(sourceObject, false, left, top, width, height);

        return;
      }


      /*
       * Dropping an object on a dataview
       */
      if (dropTarget.getAnalyzerTarget() == AnalyzerDropTarget.DATAVIEW) {
        // Only allow dropping a favorite or member on a dataview
        if (! (sourceExplorer.equalsIgnoreCase("FAVORITES") ||
            sourceExplorer.equalsIgnoreCase("MEMBER"))) {
            dtde.rejectDrop();
            return;
        }

        dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
        dtde.dropComplete(true);
        /*
         * The AnalyzerDropTarget has the following attributes:  dataview, worksheet where dataview lives
         * The worksheet has a Title attribute which stores the path to the dataview (and worksheet)
         * Update the dataview's query with the saved selection or list of dimension members
         */
        Dataview dv = dropTarget.getDataview();
        String path = dropTarget.getWorksheet().getTitle();
        Worksheet worksheet = dropTarget.getWorksheet();

        //Set active dataview here
        worksheet.setActiveDataview(dv);
        worksheet.setActiveDataviewPath(path);
        worksheet.setSelected(true);

        // Check if the object being dropped is a member selection or a favorite
        if (sourceExplorer.equalsIgnoreCase("MEMBER"))
          m_dimensionExplorer.applyDimListSelection();
        else if (sourceExplorer.equalsIgnoreCase("FAVORITES"))
          m_favoritesExplorer.applySelection(sourceObject);
      }
    }
    catch (Exception ex) {
      System.out.println("Drag and drop operation unsuccessful.");
    }
  }


  /**
   * Sets the active worksheet for this Analyzer.
   * This method is called when a user clicks on the frame for
   * the worksheet. 
   * This is required so that various operations will work properly, including 
   * Saving, Printing, Exporting, and so on.
   * 
   * @param e The InternalFrameEvent that identifies the activated internal 
   *          frame.
   * 
   * @see #setActiveWorksheet
   */
  public void internalFrameActivated(InternalFrameEvent e) {
    setActiveWorksheet((Worksheet)e.getSource());
  }

  /**
   * Cleans up when a worksheet has been closed.
   * 
   * @param e The InternalFrameEvent that identifies the worksheet to remove.
   * 
   * @see #removeWorksheet
   */
  public void internalFrameClosed(InternalFrameEvent e) {
    Worksheet worksheet = (Worksheet)e.getSource();
    removeWorksheet(worksheet);
  }

  /**
   * Null implementation for InternalFrameListener.
   */
  public void internalFrameOpened(InternalFrameEvent e) {}

  /**
   * Offers the user a chance to save a changed worksheet.
   * This method checks to see if the worksheet has been changed since it
   * was last saved. 
   * If it has been changed, then this method prompts the user to save
   * the worksheet.
   * 
   * @param e The InternalFrameEvent that identifies the worksheet that is
   *          being closed.
   *         
   * @see #save        
   * @see Worksheet#isDirty        
   */
  public void internalFrameClosing(InternalFrameEvent e) {
    // Get the worksheet
    Worksheet worksheet = (Worksheet) e.getSource();
    String message = "Save changes to " + worksheet.getTitle() + "?";

    // If the worksheet is dirty, prompt for save
    if (worksheet.isDirty()) {
      int save = JOptionPane.showConfirmDialog(this, message, "Save Changes?",
                  JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
      if (save == JOptionPane.YES_OPTION) {
        save();
      }
    }
  }

  /**
   * Null implementation for InternalFrameListener.
   */
  public void internalFrameIconified(InternalFrameEvent e) {}

  /**
   * Null implementation for InternalFrameListener.
   */
  public void internalFrameDeiconified(InternalFrameEvent e) {}

  /**
   * Null implementation for InternalFrameListener.
   */
  public void internalFrameDeactivated(InternalFrameEvent e) {}

}

