/*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 1999-2005 Julian Hyde
// Copyright (C) 2005-2013 Pentaho and others
// Copyright (C) 2006-2007 Cincom Systems, Inc.
// Copyright (C) 2006-2007 JasperSoft
// All Rights Reserved.
*/

package mondrian.gui;

import mondrian.olap.DriverManager;
import mondrian.olap.MondrianProperties;
import mondrian.olap.Util;
import mondrian.olap.Util.PropertyList;
import mondrian.server.MondrianServerRegistry;
import mondrian.util.UnionIterator;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

import org.eigenbase.xom.XMLOutput;
import org.eigenbase.xom.*;

import org.pentaho.di.core.Const;
import org.pentaho.di.core.KettleClientEnvironment;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleDatabaseException;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.ui.database.DatabaseConnectionDialog;
import org.pentaho.ui.database.Messages;
import org.pentaho.ui.database.event.DataHandler;
import org.pentaho.ui.xul.*;
import org.pentaho.ui.xul.containers.XulDialog;
import org.pentaho.ui.xul.swing.SwingXulLoader;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import javax.swing.filechooser.FileSystemView;
import javax.swing.plaf.basic.BasicArrowButton;
import javax.swing.text.DefaultEditorKit;
import javax.swing.tree.TreePath;

/**
 * @author sean
 */
public class Workbench extends javax.swing.JFrame {

    private static final long serialVersionUID = 1L;
    static String WORKBENCH_USER_HOME_DIR;
    static String WORKBENCH_CONFIG_FILE;
    static String DB_META_CONFIG_FILE;

    private static final String LAST_USED1 = "lastUsed1";
    private static final String LAST_USED1_URL = "lastUsedUrl1";
    private static final String LAST_USED2 = "lastUsed2";
    private static final String LAST_USED2_URL = "lastUsedUrl2";
    private static final String LAST_USED3 = "lastUsed3";
    private static final String LAST_USED3_URL = "lastUsedUrl3";
    private static final String LAST_USED4 = "lastUsed4";
    private static final String LAST_USED4_URL = "lastUsedUrl4";
    private static final String WorkbenchInfoResourceName =
        "mondrian.gui.resources.workbenchInfo";
    private static final String GUIResourceName = "mondrian.gui.resources.gui";
    private static final String TextResourceName =
        "mondrian.gui.resources.text";
    private static final String FILTER_SCHEMA_LIST = "FILTER_SCHEMA_LIST";

    private static final Logger LOGGER = Logger.getLogger(Workbench.class);

    private String jdbcDriverClassName;
    private String jdbcConnectionUrl;
    private String jdbcUsername;
    private String jdbcPassword;
    private String jdbcSchema;
    private boolean requireSchema;

    private JdbcMetaData jdbcMetaData;

    private final ClassLoader myClassLoader;

    private Properties workbenchProperties;
    private static ResourceBundle workbenchResourceBundle = null;

    private static I18n resourceConverter = null;

    private static int newSchema = 1;

    private String openFile = null;

    private Map<JInternalFrame, JMenuItem> schemaWindowMap =
        new HashMap<JInternalFrame, JMenuItem>();

    private final List<JInternalFrame> mdxWindows =
        new ArrayList<JInternalFrame>();
    private final List<JInternalFrame> jdbcWindows =
        new ArrayList<JInternalFrame>();
    private int windowMenuMapIndex = 1;

    private static final String KETTLE_PLUGIN_BASE_FOLDERS = "kettle-plugins,"
            + "plugins,"
            + Const.getKettleDirectory() + Const.FILE_SEPARATOR + "plugins";
    private XulDialog connectionDialog = null;
    private DataHandler connectionDialogController = null;
    private DatabaseMeta dbMeta = null;

    /**
     * Creates new form Workbench
     */
    public Workbench() {
        myClassLoader = this.getClass().getClassLoader();

        resourceConverter = getGlobalResourceConverter();

        // Setting User home directory
        WORKBENCH_USER_HOME_DIR =
            System.getProperty("user.home")
            + File.separator
            + ".schemaWorkbench";
        WORKBENCH_CONFIG_FILE =
            WORKBENCH_USER_HOME_DIR + File.separator + "workbench.properties";
        DB_META_CONFIG_FILE = WORKBENCH_USER_HOME_DIR + File.separator
                + "databaseMeta.xml";

        loadWorkbenchProperties();
        loadDatabaseMeta();
        initOptions();
        initComponents();
        loadMenubarPlugins();

        ImageIcon icon = new javax.swing.ImageIcon(
            myClassLoader.getResource(
                getResourceConverter().getGUIReference("productIcon")));

        this.setIconImage(icon.getImage());
    }

    public static I18n getGlobalResourceConverter() {
        if (resourceConverter == null) {
            ClassLoader currentClassLoader;

            ResourceBundle localGuiResourceBundle;
            ResourceBundle localTextResourceBundle;

            currentClassLoader = Workbench.class.getClassLoader();

            localGuiResourceBundle = ResourceBundle.getBundle(
                GUIResourceName, Locale.getDefault(), currentClassLoader);
            localTextResourceBundle = ResourceBundle.getBundle(
                TextResourceName, Locale.getDefault(), currentClassLoader);

            resourceConverter = new I18n(
                localGuiResourceBundle, localTextResourceBundle);
        }
        return resourceConverter;
    }

    /**
     * load properties
     */
    private void loadWorkbenchProperties() {
        workbenchProperties = new Properties();
        try {
            workbenchResourceBundle = ResourceBundle.getBundle(
                WorkbenchInfoResourceName, Locale.getDefault(),
                    myClassLoader);
            File f = new File(WORKBENCH_CONFIG_FILE);
            if (f.exists()) {
                workbenchProperties.load(new FileInputStream(f));
            } else {
                LOGGER.debug(WORKBENCH_CONFIG_FILE + " does not exist");
            }
        } catch (Exception e) {
            // TODO deal with exception
            LOGGER.error("loadWorkbenchProperties", e);
        }
    }

    /**
     * load database meta
     */
    public void loadDatabaseMeta() {
        if (dbMeta == null) {
            File file = new File(DB_META_CONFIG_FILE);
            if (file.exists()) {
                try {
                    final String fileContents =
                        FileUtils.readFileToString(file);
                    if (Util.isBlank(fileContents)) {
                        LOGGER.error(
                            "DB Meta file is empty at: "
                            + DB_META_CONFIG_FILE);
                    } else {
                        dbMeta = getDbMeta(fileContents);
                    }
                } catch (Exception e) {
                    LOGGER.error(
                        "Failed to load DB meta file at: "
                        + DB_META_CONFIG_FILE,
                        e);
                }
            }
        }

        if (dbMeta != null) {
            syncToWorkspace(dbMeta);
        }
    }

    /**
     * returns the value of a workbench property
     *
     * @param key key to lookup
     * @return the value
     */
    public String getWorkbenchProperty(String key) {
        return workbenchProperties.getProperty(key);
    }

    /**
     * set a workbench property.  Note that this does not save the property,
     * a call to storeWorkbenchProperties is required.
     *
     * @param key   property key
     * @param value property value
     */
    public void setWorkbenchProperty(String key, String value) {
        workbenchProperties.setProperty(key, value);
    }

    /**
     * save properties
     */
    public void storeWorkbenchProperties() {
        // save properties to file
        File dir = new File(WORKBENCH_USER_HOME_DIR);
        try {
            if (dir.exists()) {
                if (!dir.isDirectory()) {
                    JOptionPane.showMessageDialog(
                        this,
                        getResourceConverter().getFormattedString(
                            "workbench.user.home.not.directory",
                            "{0} is not a directory!\nPlease rename this file and retry to save configuration!",
                            WORKBENCH_USER_HOME_DIR),
                        "",
                        JOptionPane.ERROR_MESSAGE);
                    return;
                }
            } else {
                dir.mkdirs();
            }
        } catch (Exception ex) {
            LOGGER.error("storeWorkbenchProperties: mkdirs", ex);
            JOptionPane.showMessageDialog(
                this,
                getResourceConverter().getFormattedString(
                    "workbench.user.home.exception",
                    "An error is occurred creating workbench configuration directory:\n{0}\nError is: {1}",
                    WORKBENCH_USER_HOME_DIR,
                    ex.getLocalizedMessage()),
                "",
                JOptionPane.ERROR_MESSAGE);
            return;
        }

        OutputStream out = null;
        try {
            out = new FileOutputStream(
                new File(
                    WORKBENCH_CONFIG_FILE));
            workbenchProperties.store(out, "Workbench configuration");
        } catch (Exception e) {
            LOGGER.error("storeWorkbenchProperties: store", e);
            JOptionPane.showMessageDialog(
                this,
                getResourceConverter().getFormattedString(
                    "workbench.save.configuration",
                    "An error is occurred creating workbench configuration file:\n{0}\nError is: {1}",
                    WORKBENCH_CONFIG_FILE,
                    e.getLocalizedMessage()),
                "",
                JOptionPane.ERROR_MESSAGE);
        } finally {
            try {
                out.close();
            } catch (IOException eIO) {
                LOGGER.error("storeWorkbenchProperties: out.close", eIO);
            }
        }
    }

    /**
     * save database meta
     */
    public void storeDatabaseMeta() {
        if (dbMeta != null) {
            try {
                File file = new File(DB_META_CONFIG_FILE);
                PrintWriter pw = new PrintWriter(new FileWriter(file));
                pw.println(dbMeta.getXML());
                pw.close();
            } catch (IOException e) {
                LOGGER.error("storeDatabaseMeta", e);
            }
        }
    }

    /**
     * Initialize the UI options
     */
    private void initOptions() {
        requireSchema = "true".equals(getWorkbenchProperty("requireSchema"));
    }

    /**
     * This method is called from within the constructor to
     * initialize the form.
     */
    private void initComponents() {
        desktopPane = new javax.swing.JDesktopPane();
        jToolBar1 = new javax.swing.JToolBar();
        jToolBar2 = new javax.swing.JToolBar();
        toolbarNewPopupMenu = new JPopupMenu();
        toolbarNewButton = new javax.swing.JButton();
        toolbarOpenButton = new javax.swing.JButton();
        toolbarSaveButton = new javax.swing.JButton();
        toolbarSaveAsButton = new javax.swing.JButton();
        jPanel1 = new javax.swing.JPanel();
        jPanel2 = new javax.swing.JPanel();
        toolbarPreferencesButton = new javax.swing.JButton();
        requireSchemaCheckboxMenuItem = new javax.swing.JCheckBoxMenuItem();
        menuBar = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        newMenu = new javax.swing.JMenu();
        newSchemaMenuItem = new javax.swing.JMenuItem();
        newQueryMenuItem = new javax.swing.JMenuItem();
        newJDBCExplorerMenuItem = new javax.swing.JMenuItem();
        newSchemaMenuItem2 = new javax.swing.JMenuItem();
        newQueryMenuItem2 = new javax.swing.JMenuItem();
        newJDBCExplorerMenuItem2 = new javax.swing.JMenuItem();
        openMenuItem = new javax.swing.JMenuItem();
        preferencesMenuItem = new javax.swing.JMenuItem();
        lastUsed1MenuItem = new javax.swing.JMenuItem();
        lastUsed2MenuItem = new javax.swing.JMenuItem();
        lastUsed3MenuItem = new javax.swing.JMenuItem();
        lastUsed4MenuItem = new javax.swing.JMenuItem();
        saveMenuItem = new javax.swing.JMenuItem();
        saveAsMenuItem = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JSeparator();
        jSeparator2 = new javax.swing.JSeparator();
        jSeparator3 = new javax.swing.JSeparator();
        exitMenuItem = new javax.swing.JMenuItem();
        windowMenu = new javax.swing.JMenu();
        helpMenu = new javax.swing.JMenu();
        editMenu = new javax.swing.JMenu();
        cutMenuItem =
            new javax.swing.JMenuItem(new DefaultEditorKit.CutAction());
        copyMenuItem =
            new javax.swing.JMenuItem(new DefaultEditorKit.CopyAction());
        pasteMenuItem =
            new javax.swing.JMenuItem(new DefaultEditorKit.PasteAction());
        deleteMenuItem =
            new javax.swing.JMenuItem(
                new AbstractAction(
                    getResourceConverter().getString(
                        "workbench.menu.delete", "Delete"))
                {
                    private static final long serialVersionUID = 1L;
                    public void actionPerformed(ActionEvent e) {
                        JInternalFrame jf = desktopPane.getSelectedFrame();
                        if (jf != null && jf.getContentPane()
                            .getComponent(0) instanceof SchemaExplorer)
                        {
                            SchemaExplorer se =
                                (SchemaExplorer) jf.getContentPane()
                                    .getComponent(0);
                            TreePath tpath = se.tree.getSelectionPath();
                            se.delete(tpath);
                        }
                    }
                });
        aboutMenuItem = new javax.swing.JMenuItem();
        toolsMenu = new javax.swing.JMenu();
        viewMenu = new javax.swing.JMenu();
        viewXmlMenuItem = new javax.swing.JCheckBoxMenuItem();

        setTitle(
            getResourceConverter().getString(
                "workbench.panel.title", "Schema Workbench"));
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(
            new WindowAdapter() {
                public void windowClosing(WindowEvent evt) {
                    storeWorkbenchProperties();
                    storeDatabaseMeta();
                    closeAllSchemaFrames(true);
                }
            });

        getContentPane().add(desktopPane, java.awt.BorderLayout.CENTER);


        newSchemaMenuItem2.setText(
            getResourceConverter().getString(
                "workbench.menu.newSchema", "Schema"));
        newSchemaMenuItem2.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    newSchemaMenuItemActionPerformed(evt);
                }
            });

        newQueryMenuItem2.setText(
            getResourceConverter().getString(
                "workbench.menu.newQuery", "MDX Query"));
        newQueryMenuItem2.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    newQueryMenuItemActionPerformed(evt);
                }
            });


        newJDBCExplorerMenuItem2.setText(
            getResourceConverter().getString(
                "workbench.menu.newJDBC", "JDBC Explorer"));
        newJDBCExplorerMenuItem2.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    newJDBCExplorerMenuItemActionPerformed(evt);
                }
            });


        toolbarNewPopupMenu.add(newSchemaMenuItem2);
        toolbarNewPopupMenu.add(newQueryMenuItem2);
        toolbarNewPopupMenu.add(newJDBCExplorerMenuItem2);


        jPanel2.setLayout(new java.awt.BorderLayout());
        jPanel2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        jPanel2.setMaximumSize(new java.awt.Dimension(50, 28));

        toolbarNewButton.setIcon(
            new javax.swing.ImageIcon(
                getClass().getResource(
                    getResourceConverter().getGUIReference("new"))));
        toolbarNewButton.setToolTipText(
            getResourceConverter().getString(
                "workbench.toolbar.new", "New"));
        toolbarNewButton.setBorderPainted(false);
        toolbarNewButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    toolbarNewPopupMenu.show(
                        jPanel2, 0, jPanel2.getSize().height);
                }
            });

        jToolBar2.setFloatable(false);
        jToolBar2.add(toolbarNewButton);

        jPanel2.add(jToolBar2, java.awt.BorderLayout.CENTER);

        toolbarNewArrowButton = new BasicArrowButton(SwingConstants.SOUTH);
        toolbarNewArrowButton.setToolTipText(
            getResourceConverter().getString(
                "workbench.toolbar.newArrow", "New"));
        toolbarNewArrowButton.setBorderPainted(false);
        toolbarNewArrowButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    toolbarNewPopupMenu.show(
                        jPanel2, 0, jPanel2.getSize().height);
                }
            });

        jPanel2.add(toolbarNewArrowButton, java.awt.BorderLayout.EAST);

        jToolBar1.add(jPanel2, 0);


        toolbarOpenButton.setIcon(
            new javax.swing.ImageIcon(
                getClass().getResource(
                    getResourceConverter().getGUIReference("open"))));
        toolbarOpenButton.setToolTipText(
            getResourceConverter().getString(
                "workbench.toolbar.open", "Open"));
        toolbarOpenButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    openMenuItemActionPerformed(evt);
                }
            });

        jToolBar1.add(toolbarOpenButton);


        toolbarSaveButton.setIcon(
            new javax.swing.ImageIcon(
                getClass().getResource(
                    getResourceConverter().getGUIReference("save"))));
        toolbarSaveButton.setToolTipText(
            getResourceConverter().getString(
                "workbench.toolbar.save", "Save"));
        toolbarSaveButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    saveMenuItemActionPerformed(evt);
                }
            });

        jToolBar1.add(toolbarSaveButton);

        toolbarSaveAsButton.setIcon(
            new javax.swing.ImageIcon(
                getClass().getResource(
                    getResourceConverter().getGUIReference("saveAs"))));
        toolbarSaveAsButton.setToolTipText(
            getResourceConverter().getString(
                "workbench.toolbar.saveAs", "Save As"));
        toolbarSaveAsButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    saveAsMenuItemActionPerformed(evt);
                }
            });

        jToolBar1.add(toolbarSaveAsButton);

        jPanel1.setMaximumSize(new java.awt.Dimension(8, 8));
        jToolBar1.add(jPanel1);

        toolbarPreferencesButton.setIcon(
            new javax.swing.ImageIcon(
                getClass().getResource(
                    getResourceConverter().getGUIReference("preferences"))));
        toolbarPreferencesButton.setToolTipText(
            getResourceConverter().getString(
                "workbench.toolbar.connection", "Connection"));
        toolbarPreferencesButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    connectionButtonActionPerformed(evt);
                }
            });

        jToolBar1.add(toolbarPreferencesButton);


        getContentPane().add(jToolBar1, java.awt.BorderLayout.NORTH);

        fileMenu.setText(
            getResourceConverter().getString(
                "workbench.menu.file", "File"));
        fileMenu.setMnemonic(KeyEvent.VK_F);
        newMenu.setText(
            getResourceConverter().getString(
                "workbench.menu.new", "New"));

        newSchemaMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.newSchema", "Schema"));
        newSchemaMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    newSchemaMenuItemActionPerformed(evt);
                }
            });

        newMenu.add(newSchemaMenuItem);

        newQueryMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.newQuery", "MDX Query"));
        newQueryMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    newQueryMenuItemActionPerformed(evt);
                }
            });

        newMenu.add(newQueryMenuItem);

        newJDBCExplorerMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.newJDBC", "JDBC Explorer"));
        newJDBCExplorerMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    newJDBCExplorerMenuItemActionPerformed(evt);
                }
            });

        newMenu.add(newJDBCExplorerMenuItem);

        fileMenu.add(newMenu);

        openMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.open", "Open"));
        openMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    openMenuItemActionPerformed(evt);
                }
            });

        fileMenu.add(openMenuItem);

        saveMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.save", "Save"));
        saveMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    saveMenuItemActionPerformed(evt);
                }
            });

        fileMenu.add(saveMenuItem);

        saveAsMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.saveAsDot", "Save As ..."));
        saveAsMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    saveAsMenuItemActionPerformed(evt);
                }
            });

        fileMenu.add(saveAsMenuItem);

        // add last used
        fileMenu.add(jSeparator2);

        lastUsed1MenuItem.setText(getWorkbenchProperty("lastUsed1"));
        lastUsed1MenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    lastUsed1MenuItemActionPerformed(evt);
                }
            });
        fileMenu.add(lastUsed1MenuItem);

        lastUsed2MenuItem.setText(getWorkbenchProperty("lastUsed2"));
        lastUsed2MenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    lastUsed2MenuItemActionPerformed(evt);
                }
            });
        fileMenu.add(lastUsed2MenuItem);

        lastUsed3MenuItem.setText(getWorkbenchProperty("lastUsed3"));
        lastUsed3MenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    lastUsed3MenuItemActionPerformed(evt);
                }
            });
        fileMenu.add(lastUsed3MenuItem);

        lastUsed4MenuItem.setText(getWorkbenchProperty("lastUsed4"));
        lastUsed4MenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    lastUsed4MenuItemActionPerformed(evt);
                }
            });
        fileMenu.add(lastUsed4MenuItem);

        updateLastUsedMenu();
        fileMenu.add(jSeparator1);

        exitMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.exit", "Exit"));
        exitMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    exitMenuItemActionPerformed(evt);
                }
            });

        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        editMenu.setText(
            getResourceConverter().getString(
                "workbench.menu.edit", "Edit"));
        editMenu.setMnemonic(KeyEvent.VK_E);
        cutMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.cut", "Cut"));
        editMenu.add(cutMenuItem);

        copyMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.copy", "Copy"));
        editMenu.add(copyMenuItem);

        pasteMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.paste", "Paste"));
        editMenu.add(pasteMenuItem);

        editMenu.add(deleteMenuItem);

        menuBar.add(editMenu);

        viewMenu.setText(
            getResourceConverter().getString(
                "workbench.menu.view", "View"));
        viewMenu.setMnemonic(KeyEvent.VK_V);
        viewXmlMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.viewXML", "View XML"));
        viewXmlMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    viewXMLMenuItemActionPerformed(evt);
                }
            });
        viewMenu.add(viewXmlMenuItem);
        menuBar.add(viewMenu);

        toolsMenu.setText(getResourceConverter().getString(
            "workbench.menu.options", "Options"));
        toolsMenu.setMnemonic(KeyEvent.VK_O);
        preferencesMenuItem.setText(getResourceConverter().getString(
            "workbench.menu.connection", "Connection"));
        preferencesMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    connectionButtonActionPerformed(evt);
                }
            });
        toolsMenu.add(preferencesMenuItem);

        requireSchemaCheckboxMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.requireSchema", "Require Schema"));
        requireSchemaCheckboxMenuItem.setSelected(requireSchema);
        requireSchemaCheckboxMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    requireSchemaActionPerformed(e);
                }
            });

        toolsMenu.add(requireSchemaCheckboxMenuItem);
        menuBar.add(toolsMenu);


        windowMenu.setText(
            getResourceConverter().getString(
                "workbench.menu.windows", "Windows"));
        windowMenu.setMnemonic(KeyEvent.VK_W);

        cascadeMenuItem = new javax.swing.JMenuItem();
        cascadeMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.cascadeWindows", "Cascade Windows"));
        cascadeMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    cascadeMenuItemActionPerformed(evt);
                }
            });

        tileMenuItem = new javax.swing.JMenuItem();
        tileMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.tileWindows", "Tile Windows"));
        tileMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    tileMenuItemActionPerformed(evt);
                }
            });

        closeAllMenuItem = new javax.swing.JMenuItem();
        closeAllMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.closeAll", "Close All"));
        closeAllMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    closeAllMenuItemActionPerformed(evt);
                }
            });

        minimizeMenuItem = new javax.swing.JMenuItem();
        minimizeMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.minimizeAll", "Minimize All"));
        minimizeMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    minimizeMenuItemActionPerformed(evt);
                }
            });

        maximizeMenuItem = new javax.swing.JMenuItem();
        maximizeMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.maximizeAll", "Maximize All"));
        maximizeMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    maximizeMenuItemActionPerformed(evt);
                }
            });

        menuBar.add(windowMenu);

        aboutMenuItem.setText(
            getResourceConverter().getString(
                "workbench.menu.about", "About"));
        aboutMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    aboutMenuItemActionPerformed(evt);
                }
            });

        helpMenu.add(aboutMenuItem);

        helpMenu.setText(
            getResourceConverter().getString(
                "workbench.menu.help", "Help"));
        helpMenu.setMnemonic(KeyEvent.VK_H);
        menuBar.add(helpMenu);

        setJMenuBar(menuBar);

        pack();
    }

    /**
     * this method loads any available menubar plugins based on
     */
    private void loadMenubarPlugins() {
        // render any plugins
        InputStream pluginStream = null;
        try {
            Properties props = new Properties();
            pluginStream = getClass().getResourceAsStream(
                "/workbench_plugins.properties");
            if (pluginStream != null) {
                props.load(pluginStream);
                for (Object key : props.keySet()) {
                    String keystr = (String) key;
                    if (keystr.startsWith("workbench.menu-plugin")) {
                        String val = props.getProperty(keystr);
                        WorkbenchMenubarPlugin plugin =
                            (WorkbenchMenubarPlugin) Class.forName(val)
                                .newInstance();
                        plugin.setWorkbench(this);
                        plugin.addItemsToMenubar(menuBar);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (pluginStream != null) {
                    pluginStream.close();
                }
            } catch (Exception e) {
            }
        }
    }


    /**
     * @return the workbenchResourceBundle
     */
    public ResourceBundle getWorkbenchResourceBundle() {
        return workbenchResourceBundle;
    }

    /**
     * @return the resourceConverter
     */
    public I18n getResourceConverter() {
        if (resourceConverter == null) {
            resourceConverter = getGlobalResourceConverter();
        }
        return resourceConverter;
    }

    private void tileMenuItemActionPerformed(ActionEvent evt) {
        final Dimension dsize = desktopPane.getSize();
        final int desktopW = (int) dsize.getWidth();
        final int desktopH = (int) dsize.getHeight();
        final int darea = desktopW * desktopH;
        final double eacharea =
            darea
            / (schemaWindowMap.size() + mdxWindows.size() + jdbcWindows.size());
        final int wh = (int) Math.sqrt(eacharea);

        try {
            int x = 0, y = 0;
            for (JInternalFrame sf : getAllFrames()) {
                if (sf != null && !sf.isIcon()) {
                    sf.setMaximum(false);
                    sf.moveToFront();
                    if (x >= desktopW
                        || (desktopW - x) * wh < eacharea / 2)
                    {
                        // move to next row of windows
                        y += wh;
                        x = 0;
                    }
                    int sfwidth = ((x + wh) < desktopW
                        ? wh
                        : desktopW - x);
                    int sfheight = ((y + wh) < desktopH
                        ? wh
                        : desktopH - y);
                    sf.setBounds(x, y, sfwidth, sfheight);
                    x += sfwidth;
                }
            }
        } catch (Exception ex) {
            LOGGER.error("tileMenuItemActionPerformed", ex);
            // do nothing
        }
    }

    // cascade all the indows open in schema workbench
    private void cascadeMenuItemActionPerformed(
        ActionEvent evt)
    {
        try {
            int sfi = 1;
            for (JInternalFrame sf : getAllFrames()) {
                if (sf != null && !sf.isIcon()) {
                    sf.setMaximum(false);
                    sf.setLocation(30 * sfi, 30 * sfi);
                    sf.moveToFront();
                    sf.setSelected(true);
                    sfi++;
                }
            }
        } catch (Exception ex) {
            LOGGER.error("cascadeMenuItemActionPerformed", ex);
            // do nothing
        }
    }

    // close all the windows open in schema workbench
    private void closeAllMenuItemActionPerformed(ActionEvent evt) {
        closeAllSchemaFrames(false);
    }

    private void closeAllSchemaFrames(boolean exitAfterClose) {
        try {
            for (JInternalFrame sf : getAllFrames()) {
                if (sf == null) {
                    continue;
                }
                if (sf.getContentPane().getComponent(0)
                    instanceof SchemaExplorer)
                {
                    SchemaExplorer se =
                        (SchemaExplorer) sf.getContentPane().getComponent(0);
                    sf.setSelected(true);
                    int response = confirmFrameClose(sf, se);
                    switch (response) {
                    case 2:
                        // cancel
                        return;
                    case 3:
                        // not dirty
                        sf.setClosed(true);
                        break;
                    }
                } else {
                    sf.setClosed(true);
                }
            }
            // exit Schema Workbench if no files are open
            if (((schemaWindowMap.keySet().size()) == 0) && exitAfterClose) {
                System.exit(0);
            }
        } catch (Exception ex) {
            LOGGER.error("closeAllSchemaFrames", ex);
        }
    }

    private int confirmFrameClose(
        JInternalFrame schemaFrame,
        SchemaExplorer se)
    {
        if (se.isDirty()) {
            JMenuItem schemaMenuItem = schemaWindowMap.get(
                desktopPane.getSelectedFrame());
            // yes=0; no=1; cancel=2
            int answer = JOptionPane.showConfirmDialog(
                null,
                getResourceConverter().getFormattedString(
                    "workbench.saveSchemaOnClose.alert",
                    "Save changes to {0}?",
                    se.getSchemaFile().toString()),
                getResourceConverter().getString(
                    "workbench.saveSchemaOnClose.title", "Schema"),
                JOptionPane.YES_NO_CANCEL_OPTION);
            switch (answer) {
            case 0:
                saveMenuItemActionPerformed(null);
                schemaWindowMap.remove(schemaFrame);
                updateMDXCatalogList();
                schemaFrame.dispose();
                windowMenu.remove(schemaMenuItem);
                break;
            case 1:
                schemaFrame.dispose();
                schemaWindowMap.remove(schemaFrame);
                windowMenu.remove(schemaMenuItem);
                break;
            case 2:
                try {
                    schemaFrame.setClosed(false);
                    schemaFrame.show();
                } catch (Exception ex) {
                    LOGGER.error(ex);
                }
            }
            return answer;
        }
        return 3;
    }

    private void minimizeMenuItemActionPerformed(
        ActionEvent evt)
    {
        try {
            for (JInternalFrame sf : getAllFrames()) {
                if (sf != null && !sf.isIcon()) {
                    sf.setIcon(true);
                }
            }
        } catch (Exception ex) {
            LOGGER.error("minimizeMenuItemActionPerformed", ex);
            // do nothing
        }
    }

    private void maximizeMenuItemActionPerformed(
        ActionEvent evt)
    {
        try {
            for (JInternalFrame sf : getAllFrames()) {
                if (sf != null) {
                    sf.setIcon(false);
                    sf.setMaximum(true);
                }
            }
        } catch (Exception ex) {
            LOGGER.error("maximizeMenuItemActionPerformed", ex);
            // do nothing
        }
    }

    /**
     * Returns an iterable over all internal frames.
     */
    @SuppressWarnings("unchecked")
    private Iterable<JInternalFrame> getAllFrames() {
        return UnionIterator.over(
            schemaWindowMap.keySet(), mdxWindows, jdbcWindows);
    }

    private void aboutMenuItemActionPerformed(ActionEvent evt) {
        try {
            URL versionUrl = myClassLoader.getResource(
                getResourceConverter().getGUIReference( "version" ) );
            InputStream versionIn = versionUrl.openStream();
            String ver = IOUtils.toString( versionIn );
            ver = ver.replace( "PRODUCT_VERSION",
                MondrianServerRegistry.INSTANCE.getProductVersion() );
            ver = ver.replace( "COPYRIGHT_YEAR",
                MondrianServerRegistry.INSTANCE.getCopyrightYear() );
            JEditorPane jEditorPane =
                new JEditorPane( "text/html", ver );
            jEditorPane.setEditable(false);
            JScrollPane jScrollPane = new JScrollPane(jEditorPane);
            JPanel jPanel = new JPanel();
            jPanel.setLayout(new java.awt.BorderLayout());
            jPanel.add(jScrollPane, java.awt.BorderLayout.CENTER);

            JInternalFrame jf = new JInternalFrame();
            jf.setTitle("About");
            jf.getContentPane().add(jPanel);

            Dimension screenSize = this.getSize();
            int aboutW = 400;
            int aboutH = 300;
            int width = (screenSize.width / 2) - (aboutW / 2);
            int height = (screenSize.height / 2) - (aboutH / 2) - 100;
            jf.setBounds(width, height, aboutW, aboutH);
            jf.setClosable(true);

            desktopPane.add(jf);

            jf.setVisible(true);
            jf.show();
        } catch (Exception ex) {
            LOGGER.error("aboutMenuItemActionPerformed", ex);
        }
    }

    private void newJDBCExplorerMenuItemActionPerformed(
        ActionEvent evt)
    {
        try {
            if (jdbcMetaData == null) {
                getNewJdbcMetadata();
            }

            final JInternalFrame jf = new JInternalFrame();

            jf.setTitle(
                getResourceConverter().getFormattedString(
                    "workbench.new.JDBCExplorer.title",
                    "JDBC Explorer - {0} {1}",
                    jdbcMetaData.getDatabaseProductName(),
                    jdbcMetaData.getJdbcConnectionUrl()));
            getNewJdbcMetadata();

            JdbcExplorer jdbce = new JdbcExplorer(jdbcMetaData, this);

            jf.getContentPane().add(jdbce);
            jf.setBounds(0, 0, 500, 480);
            jf.setClosable(true);
            jf.setIconifiable(true);
            jf.setMaximizable(true);
            jf.setResizable(true);
            jf.setVisible(true);

            // create jdbc menu item
            final javax.swing.JMenuItem jdbcMenuItem =
                new javax.swing.JMenuItem();
            jdbcMenuItem.setText(
                getResourceConverter().getFormattedString(
                    "workbench.new.JDBCExplorer.menuitem",
                    "{0} JDBC Explorer",
                    Integer.toString(windowMenuMapIndex++)));
            jdbcMenuItem.addActionListener(
                new ActionListener() {
                    public void actionPerformed(ActionEvent evt) {
                        try {
                            if (jf.isIcon()) {
                                jf.setIcon(false);
                            } else {
                                jf.setSelected(true);
                            }
                        } catch (Exception ex) {
                            LOGGER.error("queryMenuItem", ex);
                        }
                    }
                });

            jf.addInternalFrameListener(
                new InternalFrameAdapter() {
                    public void internalFrameClosing(InternalFrameEvent e) {
                        jdbcWindows.remove(jf);
                        jf.dispose();
                        // follow this by removing file from schemaWindowMap
                        windowMenu.remove(jdbcMenuItem);
                        return;
                    }
                });

            desktopPane.add(jf);
            jf.setVisible(true);
            jf.show();

            try {
                jf.setSelected(true);
            } catch (Exception ex) {
                // do nothing
                LOGGER.error(
                    "newJDBCExplorerMenuItemActionPerformed.setSelected", ex);
            }

            jdbcWindows.add(jf);

            windowMenu.add(jdbcMenuItem, -1);
            windowMenu.add(jSeparator3, -1);
            windowMenu.add(cascadeMenuItem, -1);
            windowMenu.add(tileMenuItem, -1);
            windowMenu.add(minimizeMenuItem, -1);
            windowMenu.add(maximizeMenuItem, -1);
            windowMenu.add(closeAllMenuItem, -1);
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(
                this,
                getResourceConverter().getFormattedString(
                    "workbench.new.JDBCExplorer.exception",
                    "Database connection not successful.\n{0}",
                    ex.getLocalizedMessage()),
                getResourceConverter().getString(
                    "workbench.new.JDBCExplorer.exception.title",
                    "Database Connection Error"),
                JOptionPane.ERROR_MESSAGE);
            LOGGER.error("newJDBCExplorerMenuItemActionPerformed", ex);
        }
    }

    /**
     * Convenience method for retrieving the dbMeta instance that handles
     * required Kettle initialization.
     *
     * @param xml output of {@link DatabaseMeta#getXML()} or <code>null</code>
     * @return the current {@link DatabaseMeta} instance
     */
    private DatabaseMeta getDbMeta(String xml) {
        try {
            if (!KettleClientEnvironment.isInitialized()) {
                System.setProperty(
                    "KETTLE_PLUGIN_BASE_FOLDERS",
                    KETTLE_PLUGIN_BASE_FOLDERS);
                KettleClientEnvironment.init();
            }
            if (dbMeta != null) {
                return dbMeta;
            }
            if (xml == null) {
                dbMeta = new DatabaseMeta();
            } else {
                dbMeta = new DatabaseMeta(xml);
            }
        } catch (KettleException e) {
            throw new RuntimeException(
                getResourceConverter().getFormattedString(
                    "workbench.new.Kettle.exception",
                    "Kettle failed to initialize."),
                e);
        }
        return dbMeta;
    }

    private void connectionButtonActionPerformed(ActionEvent evt) {
        if (connectionDialog == null) {
            dbMeta = getDbMeta(null);
            connectionDialogController = new DataHandler();
            connectionDialogController.setName("dataHandler");

            XulDomContainer container = null;

            try {
                XulLoader loader = new SwingXulLoader();
                container = loader.loadXul(
                    DatabaseConnectionDialog.DIALOG_DEFINITION_FILE,
                    Messages.getBundle());
            } catch (XulException e) {
                throw new RuntimeException("Xul failed to initialize", e);
            }
            container.addEventHandler(connectionDialogController);
            connectionDialogController.loadConnectionData();
            connectionDialogController.setData(dbMeta);
            connectionDialog = (XulDialog) container.getDocumentRoot()
                    .getRootElement();
        }

        connectionDialog.show();

        dbMeta = (DatabaseMeta) connectionDialogController.getData();
        if (dbMeta.hasChanged()) {
            dbMeta.clearChanged();
            syncToWorkspace(dbMeta);
            // Enforces the JDBC preferences entered throughout all schemas
            // currently opened in the workbench.
            resetWorkbench();
        }
    }

    private void syncToWorkspace(DatabaseMeta databaseMeta) {
        // sync from dbmeta to wkspc
        try {
            jdbcConnectionUrl = databaseMeta.getURL();
        } catch (KettleDatabaseException e) {
            throw new RuntimeException("Failed to determine JDBC URL", e);
        }
        jdbcDriverClassName = databaseMeta.getDriverClass();
        jdbcUsername = databaseMeta.getUsername();
        jdbcPassword = databaseMeta.getPassword();
        //jdbcSchema = databaseMeta.getPreferredSchemaName();
        Map<String, String> options = dbMeta.getExtraOptions();

        String dbType = dbMeta.getDatabaseInterface().getPluginId();
        jdbcSchema = options.get(dbType + "." + FILTER_SCHEMA_LIST);

        // saving to workbench properties for documentation purposes only, since
        // persistence
        // of the dbmeta object is handled by a separate xml file now
        if (jdbcDriverClassName != null) {
            setWorkbenchProperty("jdbcDriverClassName", jdbcDriverClassName);
        }
        if (jdbcConnectionUrl != null) {
            setWorkbenchProperty("jdbcConnectionUrl", jdbcConnectionUrl);
        }
        if (jdbcUsername != null) {
            setWorkbenchProperty("jdbcUsername", jdbcUsername);
        }
        if (jdbcPassword != null) {
            setWorkbenchProperty("jdbcPassword", jdbcPassword);
        }
        if (jdbcSchema != null) {
            setWorkbenchProperty("jdbcSchema", jdbcSchema);
        }
    }

    private void requireSchemaActionPerformed(ActionEvent evt) {
        requireSchema = ((JCheckBoxMenuItem) evt.getSource()).isSelected();
        setWorkbenchProperty("requireSchema", "" + requireSchema);
    }


    private void newSchemaMenuItemActionPerformed(ActionEvent evt) {
        MondrianProperties.instance();
        // User's default directory. This default depends on the operating
        // system.  It is typically the "My Documents" folder on Windows, and
        // the user's home directory on Unix.
        File defaultDir =
            FileSystemView.getFileSystemView().getDefaultDirectory();
        File outputFile;
        do {
            outputFile = new File(defaultDir, "Schema" + newSchema++ + ".xml");
        } while (outputFile.exists());

        openSchemaFrame(outputFile, true);
    }

    private void newQueryMenuItemActionPerformed(ActionEvent evt) {
        JMenuItem schemaMenuItem =
            schemaWindowMap.get(desktopPane.getSelectedFrame());

        final JInternalFrame jf = new JInternalFrame();
        jf.setTitle(
            getResourceConverter().getString(
                "workbench.new.MDXQuery.title", "MDX Query"));
        QueryPanel qp = new QueryPanel(this);

        jf.getContentPane().add(qp);
        jf.setBounds(0, 0, 500, 480);
        jf.setClosable(true);
        jf.setIconifiable(true);
        jf.setMaximizable(true);
        jf.setResizable(true);
        jf.setVisible(true);

        desktopPane.add(jf);
        jf.show();
        try {
            jf.setSelected(true);
        } catch (Exception ex) {
            // do nothing
            LOGGER.error("newQueryMenuItemActionPerformed.setSelected", ex);
        }

        // add the mdx frame to this set of mdx frames for cascading method
        mdxWindows.add(jf);

        // create mdx menu item
        final javax.swing.JMenuItem queryMenuItem = new javax.swing.JMenuItem();
        queryMenuItem.setText(
            getResourceConverter().getFormattedString(
                "workbench.new.MDXQuery.menuitem",
                "{0} MDX",
                Integer.toString(windowMenuMapIndex)));
        queryMenuItem.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    try {
                        if (jf.isIcon()) {
                            jf.setIcon(false);
                        } else {
                            jf.setSelected(true);
                        }
                    } catch (Exception ex) {
                        LOGGER.error("queryMenuItem", ex);
                    }
                }
            });

        // disable mdx frame close operation to provide our handler
        // to remove frame object from mdxframeset before closing
        jf.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

        jf.addInternalFrameListener(
            new InternalFrameAdapter() {
                public void internalFrameClosing(InternalFrameEvent e) {
                    mdxWindows.remove(jf);
                    jf.dispose();
                    // follow this by removing file from schemaWindowMap
                    windowMenu.remove(queryMenuItem);
                    return;
                }
            });

        windowMenu.add(queryMenuItem, -1);
        windowMenu.add(jSeparator3, -1);
        windowMenu.add(cascadeMenuItem, -1);
        windowMenu.add(tileMenuItem, -1);
        windowMenu.add(minimizeMenuItem, -1);
        windowMenu.add(maximizeMenuItem, -1);
        windowMenu.add(closeAllMenuItem, -1);

        qp.setMenuItem(queryMenuItem);
        qp.setSchemaWindowMap(schemaWindowMap);
        qp.setWindowMenuIndex(windowMenuMapIndex++);

        if (schemaMenuItem != null) {
            qp.initConnection(schemaMenuItem.getText());
        } else {
            JOptionPane.showMessageDialog(
                this, getResourceConverter().getString(
                    "workbench.new.MDXQuery.no.selection",
                    "No Mondrian connection. Select a Schema to connect."),
                getResourceConverter().getString(
                    "workbench.new.MDXQuery.no.selection.title", "Alert"),
                JOptionPane.WARNING_MESSAGE);
        }
    }

    // inform all opened mdx query windows about the list of opened schema files
    private void updateMDXCatalogList() {
        Iterator<JInternalFrame> it = mdxWindows.iterator();
        while (it.hasNext()) {
            JInternalFrame elem = it.next();
            QueryPanel qp = (QueryPanel) elem.getContentPane().getComponent(0);
            qp.setSchemaWindowMap(schemaWindowMap);
        }
    }

    /**
     * returns the currently selected schema explorer object
     *
     * @return current schema explorer object
     */
    public SchemaExplorer getCurrentSchemaExplorer() {
        JInternalFrame jf = desktopPane.getSelectedFrame();
        if (jf != null && jf.getContentPane().getComponentCount() > 0 && jf
            .getContentPane().getComponent(0) instanceof SchemaExplorer)
        {
            return (SchemaExplorer) jf.getContentPane().getComponent(0);
        }
        return null;
    }

    private void saveAsMenuItemActionPerformed(ActionEvent evt) {
        JInternalFrame jf = desktopPane.getSelectedFrame();

        if (jf != null && jf.getContentPane()
            .getComponent(0) instanceof SchemaExplorer)
        {
            SchemaExplorer se =
                (SchemaExplorer) jf.getContentPane().getComponent(0);
            java.io.File schemaFile = se.getSchemaFile();
            java.io.File oldSchemaFile = schemaFile;
            java.io.File suggSchemaFile = new File(
                schemaFile == null
                    ? se.getSchema().name.trim() + ".xml"
                    : schemaFile.getName());
            MondrianGuiDef.Schema schema = se.getSchema();
            JFileChooser jfc = new JFileChooser();
            MondrianProperties.instance();

            jfc.setSelectedFile(suggSchemaFile);

            if (!isSchemaValid(schema)) {
                // the schema would not be re-loadable.  Abort save.
                return;
            }

            if (jfc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
                try {
                    schemaFile = jfc.getSelectedFile();
                    if (!oldSchemaFile.equals(schemaFile) && schemaFile
                        .exists())
                    {  // new file already exists, check for overwrite
                        int answer = JOptionPane.showConfirmDialog(
                            null,
                            getResourceConverter().getFormattedString(
                                "workbench.saveAs.schema.confirm",
                                "{0} schema file already exists. Do you want to replace it?",
                                schemaFile.getAbsolutePath()),
                            getResourceConverter().getString(
                                "workbench.saveAs.schema.confirm.title",
                                "Save As"),
                            JOptionPane.YES_NO_OPTION);
                        if (answer == 1) { //  no=1 ; yes=0
                            return;
                        }
                    }

                    if (se.isNewFile() && !oldSchemaFile.equals(schemaFile)) {
                        oldSchemaFile.delete();
                    }

                    if (se.isNewFile()) {
                        se.setNewFile(false);
                    }
                    se.setDirty(false);
                    se.setDirtyFlag(false);

                    XMLOutput out =
                        new XMLOutput(
                            new java.io.FileWriter(jfc.getSelectedFile()));
                    out.setAlwaysQuoteCData(true);
                    out.setIndentString("  ");
                    schema.displayXML(out);
                    se.setSchemaFile(schemaFile);
                    se.setTitle();  // sets title of iframe
                    setLastUsed(
                        jfc.getSelectedFile().getName(),
                        jfc.getSelectedFile().toURI().toURL().toString());

                    // Update menu item with new file name, then update catalog
                    // list for mdx queries
                    JMenuItem sMenuItem = schemaWindowMap.get(jf);
                    String mtexttokens[] = sMenuItem.getText().split(" ");
                    sMenuItem.setText(
                        mtexttokens[0] + " " + se.getSchemaFile().getName());
                    // Schema menu item updated, now update mdx query windows
                    // with updated catalog list.
                    updateMDXCatalogList();
                } catch (Exception ex) {
                    LOGGER.error(ex);
                }
            }
        }
    }

    /**
     * Validates that the schema can be parsed and loaded,
     * showing a warning message if any errors are encountered.
     */
    private boolean isSchemaValid(MondrianGuiDef.Schema schema) {
        try {
            StringWriter writer = new StringWriter();
            XMLOutput xmlOutput =  new XMLOutput(writer);
            schema.displayXML(xmlOutput);
            Parser xmlParser = XOMUtil.createDefaultParser();
            Reader reader = new StringReader(writer.getBuffer().toString());
            // attempt to create a new schema
            new MondrianGuiDef.Schema(xmlParser.parse(reader));
        } catch (XOMException e) {
            JOptionPane.showMessageDialog(
                this,
                getResourceConverter().getFormattedString(
                    "workbench.save.invalid.schema",
                    "Please correct the following error before saving:",
                    e.getLocalizedMessage()),
                getResourceConverter().getFormattedString(
                    "workbench.save.invalid.schema.title",
                    "Cannot Save"),
                JOptionPane.WARNING_MESSAGE);
            return false;
        }
        return true;
    }

    private void viewXMLMenuItemActionPerformed(ActionEvent evt) {
        JInternalFrame jf = desktopPane.getSelectedFrame();
        boolean oldValue = viewXmlMenuItem.getState();
        if (jf != null
            && jf.getContentPane().getComponent(0) instanceof SchemaExplorer)
        {
            SchemaExplorer se =
                (SchemaExplorer) jf.getContentPane().getComponent(0);
            // Call schema explorer's view xml event and update the workbench's
            // view menu accordingly'
            ((JCheckBoxMenuItem) evt.getSource()).setSelected(se.editMode(evt));
            return;
        }
        viewXmlMenuItem.setSelected(!oldValue);
    }

    public void saveMenuItemActionPerformed(ActionEvent evt) {
        JInternalFrame jf = desktopPane.getSelectedFrame();

        // Don't save if nothing there
        if (jf == null || jf.getContentPane() == null) {
            return;
        }

        if (jf.getContentPane().getComponent(0) instanceof SchemaExplorer) {
            SchemaExplorer se =
                (SchemaExplorer) jf.getContentPane().getComponent(0);

            java.io.File schemaFile = se.getSchemaFile();

            if (se.isNewFile()) {
                saveAsMenuItemActionPerformed(evt);
                return;
            }

            se.setDirty(false);
            se.setDirtyFlag(false);
            se.setTitle();  // sets title of iframe

            MondrianGuiDef.Schema schema = se.getSchema();

            if (!isSchemaValid(schema)) {
                // the schema would not be re-loadable.  Abort save.
                return;
            }

            MondrianProperties.instance();
            try {
                XMLOutput out = new XMLOutput(new FileWriter(schemaFile));
                out.setAlwaysQuoteCData(true);
                out.setIndentString("  ");
                schema.displayXML(out);
                setLastUsed(
                    schemaFile.getName(),
                    schemaFile.toURI().toURL().toString());
            } catch (Exception ex) {
                LOGGER.error("saveMenuItemActionPerformed", ex);
            }
        }
    }

    /**
     * Set last used in properties file
     */
    private void setLastUsed(String name, String url) {
        int match = 4;
        String luName = null;
        String propname = null;
        String lastUsed = "lastUsed";
        String lastUsedUrl = "lastUsedUrl";
        for (int i = 1; i <= 4; i++) {
            propname = lastUsed + i;
            luName = getWorkbenchProperty(propname);

            if (luName != null && luName.equals(name)) {
                match = i;
                break;
            }
        }

        for (int i = match; i > 1; i--) {
            if (getWorkbenchProperty(lastUsed + (i - 1)) != null) {
                setWorkbenchProperty(
                    lastUsed + i, getWorkbenchProperty(
                        lastUsed + (i - 1)));
                setWorkbenchProperty(
                    lastUsedUrl + i, getWorkbenchProperty(
                        lastUsedUrl + (i - 1)));
            }
        }

        setWorkbenchProperty(LAST_USED1, name);
        setWorkbenchProperty(LAST_USED1_URL, url);
        updateLastUsedMenu();
        storeWorkbenchProperties();
        storeDatabaseMeta();
    }

    private void updateLastUsedMenu() {
        if (getWorkbenchProperty(LAST_USED1) == null) {
            jSeparator2.setVisible(false);
        } else {
            jSeparator2.setVisible(true);
        }

        if (getWorkbenchProperty(LAST_USED1) != null) {
            lastUsed1MenuItem.setVisible(true);
        } else {
            lastUsed1MenuItem.setVisible(false);
        }
        if (getWorkbenchProperty(LAST_USED2) != null) {
            lastUsed2MenuItem.setVisible(true);
        } else {
            lastUsed2MenuItem.setVisible(false);
        }
        if (getWorkbenchProperty(LAST_USED3) != null) {
            lastUsed3MenuItem.setVisible(true);
        } else {
            lastUsed3MenuItem.setVisible(false);
        }
        if (getWorkbenchProperty(LAST_USED4) != null) {
            lastUsed4MenuItem.setVisible(true);
        } else {
            lastUsed4MenuItem.setVisible(false);
        }

        lastUsed1MenuItem.setText(getWorkbenchProperty(LAST_USED1));
        lastUsed2MenuItem.setText(getWorkbenchProperty(LAST_USED2));
        lastUsed3MenuItem.setText(getWorkbenchProperty(LAST_USED3));
        lastUsed4MenuItem.setText(getWorkbenchProperty(LAST_USED4));
    }

    private void lastUsed1MenuItemActionPerformed(ActionEvent evt) {
        try {
            openSchemaFrame(
                new File(new URI(getWorkbenchProperty(LAST_USED1_URL))), false);
        } catch (Exception e) {
            // probably URISyntaxException
            LOGGER.error("lastUsed1MenuItemActionPerformed", e);
        }
    }

    private void lastUsed2MenuItemActionPerformed(ActionEvent evt) {
        try {
            openSchemaFrame(
                new File(new URI(getWorkbenchProperty(LAST_USED2_URL))), false);
            setLastUsed(
                getWorkbenchProperty(LAST_USED2), getWorkbenchProperty(
                    LAST_USED2_URL));
        } catch (URISyntaxException e) {
            LOGGER.error("lastUsed2MenuItemActionPerformed", e);
        }
    }

    private void lastUsed3MenuItemActionPerformed(ActionEvent evt) {
        try {
            openSchemaFrame(
                new File(new URI(getWorkbenchProperty(LAST_USED3_URL))), false);
            setLastUsed(
                getWorkbenchProperty(LAST_USED3), getWorkbenchProperty(
                    LAST_USED3_URL));
        } catch (URISyntaxException e) {
            LOGGER.error("lastUsed3MenuItemActionPerformed", e);
        }
    }

    private void lastUsed4MenuItemActionPerformed(ActionEvent evt) {
        try {
            openSchemaFrame(
                new File(new URI(getWorkbenchProperty(LAST_USED4_URL))), false);
            setLastUsed(
                getWorkbenchProperty(LAST_USED4), getWorkbenchProperty(
                    LAST_USED4_URL));
        } catch (URISyntaxException e) {
            LOGGER.error("lastUsed4MenuItemActionPerformed", e);
        }
    }

    private void openSchemaFrame(File file, boolean newFile) {
        try {
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

            if (!newFile) {
                // check if file not already open
                if (checkFileOpen(file)) {
                    return;
                }
                // check if schema file exists
                if (!file.exists()) {
                    JOptionPane.showMessageDialog(
                        this,
                        getResourceConverter().getFormattedString(
                            "workbench.open.schema.not.found",
                            "{0} File not found.",
                            file.getAbsolutePath()),
                        getResourceConverter().getString(
                            "workbench.open.schema.not.found.title", "Alert"),
                        JOptionPane.WARNING_MESSAGE);
                    return;
                }
                // check if file is writable
                if (!file.canWrite()) {
                    JOptionPane.showMessageDialog(
                        this,
                        getResourceConverter().getFormattedString(
                            "workbench.open.schema.not.writeable",
                            "{0} is not writeable.",
                            file.getAbsolutePath()),
                        getResourceConverter().getString(
                            "workbench.open.schema.not.writeable.title",
                            "Alert"),
                        JOptionPane.WARNING_MESSAGE);
                    return;
                }
                checkSchemaFile(file);
            }

            final JInternalFrame schemaFrame = new JInternalFrame();
            schemaFrame.setTitle(
                getResourceConverter().getFormattedString(
                    "workbench.open.schema.title",
                    "Schema - {0}",
                    file.getName()));

            getNewJdbcMetadata();

            schemaFrame.getContentPane().add(
                new SchemaExplorer(
                    this, file, jdbcMetaData, newFile, schemaFrame));

            String errorOpening =
                ((SchemaExplorer) schemaFrame.getContentPane().getComponent(0))
                    .getErrMsg();
            if (errorOpening != null) {
                JOptionPane.showMessageDialog(
                    this,
                    getResourceConverter().getFormattedString(
                        "workbench.open.schema.error",
                        "Error opening schema - {0}.",
                        errorOpening),
                    getResourceConverter().getString(
                        "workbench.open.schema.error.title", "Error"),
                    JOptionPane.ERROR_MESSAGE);
                schemaFrame.setClosed(true);
                return;
            }

            schemaFrame.setBounds(0, 0, 1000, 650);
            schemaFrame.setClosable(true);
            schemaFrame.setIconifiable(true);
            schemaFrame.setMaximizable(true);
            schemaFrame.setResizable(true);
            schemaFrame.setVisible(true);

            desktopPane.add(
                schemaFrame, javax.swing.JLayeredPane.DEFAULT_LAYER);
            schemaFrame.show();
            schemaFrame.setMaximum(true);

            displayWarningOnFailedConnection();

            final javax.swing.JMenuItem schemaMenuItem =
                new javax.swing.JMenuItem();
            schemaMenuItem.setText(windowMenuMapIndex++ + " " + file.getName());
            schemaMenuItem.addActionListener(
                new ActionListener() {
                    public void actionPerformed(ActionEvent evt) {
                        try {
                            if (schemaFrame.isIcon()) {
                                schemaFrame.setIcon(false);
                            } else {
                                schemaFrame.setSelected(true);
                            }
                        } catch (Exception ex) {
                            LOGGER.error("schemaMenuItem", ex);
                        }
                    }
                });

            windowMenu.add(schemaMenuItem, 0);
            windowMenu.setEnabled(true);

            windowMenu.add(jSeparator3, -1);
            windowMenu.add(cascadeMenuItem, -1);
            windowMenu.add(tileMenuItem, -1);
            windowMenu.add(minimizeMenuItem, -1);
            windowMenu.add(maximizeMenuItem, -1);
            windowMenu.add(closeAllMenuItem, -1);

            // add the file details in menu map
            schemaWindowMap.put(schemaFrame, schemaMenuItem);
            updateMDXCatalogList();

            schemaFrame.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

            schemaFrame.addInternalFrameListener(
                new InternalFrameAdapter() {
                    public void internalFrameClosing(InternalFrameEvent e) {
                        if (schemaFrame.getContentPane()
                            .getComponent(0) instanceof SchemaExplorer)
                        {
                            SchemaExplorer se =
                                (SchemaExplorer) schemaFrame.getContentPane()
                                    .getComponent(0);
                            int response = confirmFrameClose(schemaFrame, se);
                            if (response == 3) {    // not dirty
                                if (se.isNewFile()) {
                                    se.getSchemaFile().delete();
                                }
                                // default case for no save and not dirty
                                schemaWindowMap.remove(schemaFrame);
                                updateMDXCatalogList();
                                schemaFrame.dispose();
                                windowMenu.remove(schemaMenuItem);
                            }
                        }
                    }
                });

            schemaFrame.setFocusable(true);
            schemaFrame.addFocusListener(
                new FocusAdapter() {
                    public void focusGained(FocusEvent e) {
                        if (schemaFrame.getContentPane()
                            .getComponent(0) instanceof SchemaExplorer)
                        {
                            SchemaExplorer se = (SchemaExplorer)
                                schemaFrame.getContentPane().getComponent(0);
                            // update view menu based on schemaframe who gained
                            // focus
                            viewXmlMenuItem.setSelected(
                                se.isEditModeXML());
                        }
                    }

                    public void focusLost(FocusEvent e) {
                        if (schemaFrame.getContentPane()
                            .getComponent(0) instanceof SchemaExplorer)
                        {
                            SchemaExplorer se = (SchemaExplorer)
                                schemaFrame.getContentPane().getComponent(0);
                            // update view menu based on
                            viewXmlMenuItem.setSelected(
                                se.isEditModeXML());
                        }
                    }
                });
            viewXmlMenuItem.setSelected(false);
        } catch (Exception ex) {
            LOGGER.error("openSchemaFrame", ex);
        } finally {
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        }
    }

    private void openMenuItemActionPerformed(ActionEvent evt) {
        JFileChooser jfc = new JFileChooser();
        try {
            jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
            jfc.setFileFilter(
                new javax.swing.filechooser.FileFilter() {
                    public boolean accept(File pathname) {
                        return pathname.getName().toLowerCase().endsWith(".xml")
                               || pathname.isDirectory();
                    }

                    public String getDescription() {
                        return getResourceConverter().getString(
                            "workbench.open.schema.file.type",
                            "Mondrian Schema files (*.xml)");
                    }
                });

            String lastUsed = getWorkbenchProperty(LAST_USED1_URL);

            if (lastUsed != null) {
                jfc.setCurrentDirectory(new File(new URI(lastUsed)));
            }
        } catch (Exception ex) {
            LOGGER.error("Could not set file chooser", ex);
        }
        MondrianProperties.instance();
        if (jfc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            try {
                setLastUsed(
                    jfc.getSelectedFile().getName(),
                    jfc.getSelectedFile().toURI().toURL().toString());
            } catch (MalformedURLException e) {
                LOGGER.error(e);
            }

            openSchemaFrame(jfc.getSelectedFile(), false);
        }
    }

    // checks if file already open in schema explorer
    private boolean checkFileOpen(File file) {
        Iterator<JInternalFrame> it = schemaWindowMap.keySet().iterator();
        // keys=schemaframes
        while (it.hasNext()) {
            JInternalFrame elem = it.next();
            File f = ((SchemaExplorer) elem.getContentPane().getComponent(0))
                .getSchemaFile();
            if (f.equals(file)) {
                try {
                    // make the schema file active
                    elem.setSelected(true);
                    return true;
                } catch (Exception ex) {
                    // remove file from map as schema frame does not exist
                    schemaWindowMap.remove(elem);
                    break;
                }
            }
        }
        return false;
    }

    private void getNewJdbcMetadata() {
        jdbcMetaData = new JdbcMetaData(
            this,
            jdbcDriverClassName,
            jdbcConnectionUrl,
            jdbcUsername,
            jdbcPassword,
            jdbcSchema,
            requireSchema);
    }

    /**
     * Updates the JdbcMetaData for each SchemaExplorer contained in each Schema
     * Frame currently opened based on the JDBC preferences entered.
     */
    private void resetWorkbench() {
        getNewJdbcMetadata();

        Iterator<JInternalFrame> theSchemaFrames =
            schemaWindowMap.keySet().iterator();
        while (theSchemaFrames.hasNext()) {
            JInternalFrame theSchemaFrame =
                theSchemaFrames.next();
            SchemaExplorer theSchemaExplorer =
                (SchemaExplorer) theSchemaFrame.getContentPane()
                    .getComponent(0);
            File theFile = theSchemaExplorer.getSchemaFile();
            checkSchemaFile(theFile);
            theSchemaExplorer.resetMetaData(jdbcMetaData);
            theSchemaExplorer.getTreeUpdater().update();
            theSchemaFrame.updateUI();
        }
        // EC: If the JDBC preferences entered then display a warning.
        displayWarningOnFailedConnection();

        for (JInternalFrame jdbcFrame : jdbcWindows) {
            JdbcExplorer explorer =
                (JdbcExplorer) jdbcFrame.getContentPane().getComponent(0);
            explorer.resetMetaData(jdbcMetaData);

            jdbcFrame.setTitle(
                getResourceConverter().getFormattedString(
                    "workbench.new.JDBCExplorer.title",
                    "JDBC Explorer - {0} {1}",
                    jdbcMetaData.getDatabaseProductName(),
                    jdbcMetaData.getJdbcConnectionUrl()));

            explorer.getTreeUpdater().update();
            explorer.updateUI();
        }
    }

    /**
     * Display jdbc connection status warning, if connection is uncsuccessful.
     */
    private void displayWarningOnFailedConnection() {
        if (jdbcMetaData != null && jdbcMetaData.getErrMsg() != null) {
            JOptionPane.showMessageDialog(
                this,
                getResourceConverter().getFormattedString(
                    "workbench.open.schema.jdbc.error",
                    "Database connection could not be done.\n{0}\nAll validations related to database will be ignored.",
                    jdbcMetaData.getErrMsg()),
                getResourceConverter().getString(
                    "workbench.open.schema.jdbc.error.title", "Alert"),
                JOptionPane.WARNING_MESSAGE);
        }
    }

    /**
     * Check if schema file is valid by initiating a mondrian connection.
     */
    private void checkSchemaFile(File file) {
        try {
            // this connection parses the catalog file which if invalid will
            // throw exception
            PropertyList list = new PropertyList();
            list.put("Provider", "mondrian");
            list.put("Jdbc", jdbcConnectionUrl);
            list.put("Catalog", file.toURI().toURL().toString());
            list.put("JdbcDrivers", jdbcDriverClassName);
            if (jdbcUsername != null && jdbcUsername.length() > 0) {
                list.put("JdbcUser", jdbcUsername);
            }
            if (jdbcPassword != null && jdbcPassword.length() > 0) {
                list.put("JdbcPassword", jdbcPassword);
            }

            DriverManager.getConnection(list, null);
        } catch (Exception ex) {
            LOGGER.error(
                "Exception : Schema file "
                + file.getAbsolutePath()
                + " is invalid."
                + ex.getMessage(), ex);
        } catch (Error err) {
            LOGGER.error(
                "Error : Schema file "
                + file.getAbsolutePath()
                + " is invalid."
                + err.getMessage(), err);
        }
    }


    private void exitMenuItemActionPerformed(ActionEvent evt) {
        storeWorkbenchProperties();
        storeDatabaseMeta();
        closeAllSchemaFrames(true);
    }

    /**
     * Parses arguments passed into Workbench.
     *
     * <p>Right now, it's very simple.  Just search through the list of
     * arguments.  If it begins with -f=, then the rest is a file name.  Ignore
     * any others.  We can make this more complicated later if we need to.
     *
     * @param args the command line arguments
     */
    private void parseArgs(String args[]) {
        for (int argNum = 0; argNum < args.length; argNum++) {
            if (args[argNum].startsWith("-f=")) {
                openFile = args[argNum].substring(3);
            }
        }
    }

    public String getTooltip(String titleName) {
        try {
            return getWorkbenchResourceBundle().getString(titleName);
        } catch (MissingResourceException e) {
            return getResourceConverter().getFormattedString(
                "workbench.tooltip.error",
                "No help available for {0}",
                titleName);
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        Workbench w = null;
        try {
            w = new Workbench();
            w.parseArgs(args);
            w.setSize(800, 600);
            // if user specified a file to open, do so now.
            if (w.openFile != null) {
                File f = new File(w.openFile);
                if (f.canRead()) {
                    w.openSchemaFrame(
                        f.getAbsoluteFile(),
                        // parameter to indicate this is a new or existing
                        // catalog file
                        false);
                }
            }
            w.setVisible(true);
        } catch (Throwable ex) {
            if (w != null) {
            JOptionPane.showMessageDialog(
                w,
                w.getResourceConverter().getFormattedString(
                    "workbench.main.uncoverable_error",
                    "Pentaho Schema Workbench has encountered an unrecoverable error. \n{0}",
                    ex.getLocalizedMessage()),
                w.getResourceConverter().getString(
                    "workbench.main.uncoverable_error.title",
                    "PSW Fatal Error"),
                JOptionPane.ERROR_MESSAGE);
            }
            LOGGER.error("main", ex);
        }
    }

    // Variables declaration - do not modify
    private javax.swing.JButton toolbarSaveAsButton;
    private javax.swing.JMenuItem openMenuItem;
    private javax.swing.JMenuItem lastUsed1MenuItem;
    private javax.swing.JMenuItem lastUsed2MenuItem;
    private javax.swing.JMenuItem lastUsed3MenuItem;
    private javax.swing.JMenuItem lastUsed4MenuItem;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JMenuItem newQueryMenuItem;
    private javax.swing.JMenuItem newQueryMenuItem2;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JButton toolbarOpenButton;
    private javax.swing.JButton toolbarNewButton;
    private javax.swing.JButton toolbarNewArrowButton;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JSeparator jSeparator3;
    private javax.swing.JMenuItem cutMenuItem;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JMenuItem saveMenuItem;
    private javax.swing.JMenuItem newJDBCExplorerMenuItem;
    private javax.swing.JMenuItem newJDBCExplorerMenuItem2;
    private javax.swing.JButton toolbarSaveButton;
    private javax.swing.JMenuItem copyMenuItem;
    private javax.swing.JDesktopPane desktopPane;
    private javax.swing.JMenu viewMenu;
    private javax.swing.JMenu toolsMenu;
    private javax.swing.JMenu newMenu;
    private javax.swing.JMenuItem deleteMenuItem;
    private javax.swing.JMenuItem newSchemaMenuItem;
    private javax.swing.JMenuItem newSchemaMenuItem2;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JButton toolbarPreferencesButton;
    private javax.swing.JCheckBoxMenuItem requireSchemaCheckboxMenuItem;
    private javax.swing.JMenu editMenu;
    private javax.swing.JMenuItem pasteMenuItem;
    private javax.swing.JMenuItem preferencesMenuItem;
    private javax.swing.JCheckBoxMenuItem viewXmlMenuItem;
    private javax.swing.JMenuItem saveAsMenuItem;
    private javax.swing.JToolBar jToolBar1;
    private javax.swing.JToolBar jToolBar2;
    private javax.swing.JPopupMenu toolbarNewPopupMenu;
    private javax.swing.JMenu windowMenu;
    private javax.swing.JMenu helpMenu;
    private javax.swing.JMenuItem aboutMenuItem;
    private javax.swing.JMenuItem cascadeMenuItem;
    private javax.swing.JMenuItem tileMenuItem;
    private javax.swing.JMenuItem minimizeMenuItem;
    private javax.swing.JMenuItem maximizeMenuItem;
    private javax.swing.JMenuItem closeAllMenuItem;
// End of variables declaration

    /**
     * Used by schema framewhen it uses 'view xml' to update view xml menu item
     */
    public javax.swing.JCheckBoxMenuItem getViewXmlMenuItem() {
        return viewXmlMenuItem;
    }
}

// End Workbench.java
