package com.dbxml.db.admin;

/*
 * dbXML - Native XML Database
 * Copyright (C) 1999-2004  The dbXML Group, L.L.C.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the isFree Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Id: Admin.java,v 1.13 2004/08/02 19:04:17 bradford Exp $
 */

import java.awt.*;
import javax.swing.*;

import com.dbxml.db.admin.components.DBBrowser;
import com.dbxml.db.admin.components.GridEditor;
import com.dbxml.db.admin.components.TextEditor;
import com.dbxml.db.admin.components.XSLTViewer;
import com.dbxml.db.admin.dialogs.AboutDialog;
import com.dbxml.db.admin.dialogs.PreferencesDialog;
import com.dbxml.db.admin.dialogs.Splash;
import com.dbxml.db.admin.nodes.AdminNode;
import com.dbxml.db.admin.nodes.HasCollection;
import com.dbxml.db.admin.nodes.HasDocWrapper;
import com.dbxml.db.admin.nodes.HasStorage;
import com.dbxml.db.admin.nodes.RootNode;
import com.dbxml.db.admin.swing.JLabelListCellRenderer;
import com.dbxml.db.admin.swing.SyntaxTextArea;
import com.dbxml.db.admin.xmleditor.ElementResourceMap;
import com.dbxml.db.client.CollectionClient;
import com.dbxml.db.client.ResultSetClient;
import com.dbxml.db.client.dbXMLClient;
import com.dbxml.db.common.fulltext.FullTextQueryResolver;
import com.dbxml.db.common.xpath.XPathQueryResolver;
import com.dbxml.db.common.xslt.XSLTQueryResolver;
import com.dbxml.db.common.xupdate.XUpdateQueryResolver;
import com.dbxml.db.core.query.Query;
import com.dbxml.db.core.query.helpers.ResultSetWrapper;
import com.dbxml.db.server.dbXML;
import com.dbxml.util.Stopwatch;
import com.dbxml.xml.dom.DOMHelper;
import com.dbxml.xml.dom.TextWriter;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.MenuEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * Admin
 */

public final class Admin extends JFrame {
   private static final AdminNode[] EmptyAdminNodes = new AdminNode[0];

   public static final ElementResourceMap DefaultResMap = new ElementResourceMap();
   public static final ElementResourceMap SystemResMap = new ElementResourceMap();

   static {
      SystemResMap.setIcon("servers", new ImageIcon(Admin.class.getResource("nodes/servers_mini.gif")));
      SystemResMap.setIcon("server", new ImageIcon(Admin.class.getResource("nodes/server_mini.gif")));
      SystemResMap.setIcon("server_nc", new ImageIcon(Admin.class.getResource("nodes/server_nc_mini.gif")));
      SystemResMap.setIcon("services", new ImageIcon(Admin.class.getResource("nodes/servers_mini.gif")));
      SystemResMap.setIcon("service", new ImageIcon(Admin.class.getResource("nodes/server_mini.gif")));
      SystemResMap.setIcon("extensions", new ImageIcon(Admin.class.getResource("nodes/classes_mini.gif")));
      SystemResMap.setIcon("extension", new ImageIcon(Admin.class.getResource("nodes/class_mini.gif")));
      SystemResMap.setIcon("schemas", new ImageIcon(Admin.class.getResource("nodes/schemas_mini.gif")));
      SystemResMap.setIcon("schema", new ImageIcon(Admin.class.getResource("nodes/schema_mini.gif")));
      SystemResMap.setIcon("collections", new ImageIcon(Admin.class.getResource("nodes/databases_mini.gif")));
      SystemResMap.setIcon("collection", new ImageIcon(Admin.class.getResource("nodes/database_mini.gif")));
      SystemResMap.setIcon("database", new ImageIcon(Admin.class.getResource("nodes/database_mini.gif")));
      SystemResMap.setIcon("documents", new ImageIcon(Admin.class.getResource("nodes/docs_mini.gif")));
      SystemResMap.setIcon("document", new ImageIcon(Admin.class.getResource("nodes/doc_mini.gif")));
      SystemResMap.setIcon("procedures", new ImageIcon(Admin.class.getResource("nodes/procs_mini.gif")));
      SystemResMap.setIcon("procedure", new ImageIcon(Admin.class.getResource("nodes/proc_mini.gif")));
      SystemResMap.setIcon("triggers", new ImageIcon(Admin.class.getResource("nodes/triggers_mini.gif")));
      SystemResMap.setIcon("trigger", new ImageIcon(Admin.class.getResource("nodes/trigger_mini.gif")));
      SystemResMap.setIcon("indexes", new ImageIcon(Admin.class.getResource("nodes/indexes_mini.gif")));
      SystemResMap.setIcon("index", new ImageIcon(Admin.class.getResource("nodes/index_mini.gif")));
      SystemResMap.setIcon("users", new ImageIcon(Admin.class.getResource("nodes/users_mini.gif")));
      SystemResMap.setIcon("user", new ImageIcon(Admin.class.getResource("nodes/user_mini.gif")));
      SystemResMap.setIcon("roles", new ImageIcon(Admin.class.getResource("nodes/roles_mini.gif")));
      SystemResMap.setIcon("role", new ImageIcon(Admin.class.getResource("nodes/role_mini.gif")));
   }

   private static Splash splash;
   private static Admin admin;

   public DBBrowser browser;
   public TextEditor textEditor = new TextEditor();
   public GridEditor gridEditor = new GridEditor();
   public XSLTViewer xsltViewer = new XSLTViewer();

   private AdminConfig cfg;
   private DocWrapper doc;
   private TabbedNodeEditor nodeEditor;
   private boolean ignoreChange;
   private boolean readOnly;
   private boolean newDocument;

   private boolean showToolbar = true;
   private boolean showExplorer = true;
   private boolean showQuery = true;
   private boolean showMessages;
   private boolean showStatusbar = true;

   private int locQuery = -1;
   private int locMessage = -1;
   private int locExplorer = -1;

   private String[] queryText = new String[8];
   private int oldQueryTextIdx = -1;

   JPanel contentPane;
   JMenuBar mnuMain = new JMenuBar();
   JMenu mnuFile = new JMenu();
   JMenu mnuEdit = new JMenu();
   JMenu mnuHelp = new JMenu();
   JMenuItem mnuFileExit = new JMenuItem();
   JMenuItem mnuEditUndo = new JMenuItem();
   JMenuItem mnuEditCut = new JMenuItem();
   JMenuItem mnuEditCopy = new JMenuItem();
   JMenuItem mnuEditPaste = new JMenuItem();
   JMenuItem mnuEditFind = new JMenuItem();
   JMenuItem mnuEditFindNext = new JMenuItem();
   JMenuItem mnuFilePreferences = new JMenuItem();
   JMenuItem mnuHelpContents = new JMenuItem();
   JMenuItem mnuHelpAbout = new JMenuItem();
   JToolBar toolBar = new JToolBar();
   JButton btnOpen = new JButton();
   JButton btnSave = new JButton();
   JButton btnAbout = new JButton();
   ImageIcon imgNew;
   ImageIcon imgOpen;
   ImageIcon imgSave;
   ImageIcon imgAbout;
   ImageIcon imgCut;
   ImageIcon imgCopy;
   ImageIcon imgPaste;
   ImageIcon imgInsert;
   ImageIcon imgRemove;
   ImageIcon imgSearch;
   ImageIcon imgUndo;
   ImageIcon imgTextView;
   ImageIcon imgGridView;
   ImageIcon imgPlainView;
   ImageIcon imgXSLTView;
   ImageIcon imgIcon;
   ImageIcon imgQryBefore;
   ImageIcon imgQryAfter;
   ImageIcon imgQryRemove;
   ImageIcon imgQryAppend;
   ImageIcon imgQryUpdate;
   ImageIcon imgQryXPath;
   ImageIcon imgQryXSLT;
   BorderLayout contentPaneLayout = new BorderLayout();
   JScrollPane scrollBrowser = new JScrollPane();
   JSplitPane splitQuery = new JSplitPane();
   JPanel pnlQueryEdit = new JPanel();
   BorderLayout pnlQueryEditLayout = new BorderLayout();
   JTabbedPane paneEdit = new JTabbedPane();
   JButton btnNew = new JButton();
   Component strut1;
   Component strut2;
   JButton btnCut = new JButton();
   JButton btnCopy = new JButton();
   JButton btnPaste = new JButton();
   JButton btnUndo = new JButton();
   JButton btnSearch = new JButton();
   Component strut3;
   JMenu mnuObject = new JMenu();
   JComboBox cmbQueryType = new JComboBox();
   JButton btnQuery = new JButton();
   TitledBorder brdTitled;
   Border brdQueryEdit;
   JPanel pnlQueryButtons = new JPanel();
   BorderLayout layoutPnlQueryButtons = new BorderLayout();
   SyntaxTextArea txtQuery = new SyntaxTextArea();
   JPanel pnlStatus = new JPanel();
   JLabel statusBar = new JLabel();
   JPanel pnlStatusInfo = new JPanel();
   BorderLayout pnlStatusLayout = new BorderLayout();
   JLabel lblColName = new JLabel();
   JLabel lblDocName = new JLabel();
   FlowLayout pnlStatusInfoLayout = new FlowLayout();
   Border brdTwoPixel;
   JLabel lblQueryType = new JLabel();
   JMenu mnuView = new JMenu();
   JCheckBoxMenuItem mnuViewExplorer = new JCheckBoxMenuItem();
   JCheckBoxMenuItem mnuViewQuery = new JCheckBoxMenuItem();
   JCheckBoxMenuItem mnuViewMessages = new JCheckBoxMenuItem();
   JCheckBoxMenuItem mnuViewToolbar = new JCheckBoxMenuItem();
   JCheckBoxMenuItem mnuViewStatusBar = new JCheckBoxMenuItem();
   JSplitPane splitMessage = new JSplitPane();
   JSplitPane splitExplorer = new JSplitPane();
   JScrollPane scrollMessages = new JScrollPane();
   JTextArea txtMessages = new JTextArea();
   JPanel pnlGrowBox = new JPanel();
   JMenuItem mnuEditBeautify = new JMenuItem();

   public static void main(String[] args) {
      splash = new Splash();

      new Admin();
      admin.show();
   }

   public static Admin getInstance() {
      return admin;
   }

   public AdminConfig getAdminConfig() {
      return cfg;
   }

   public void setEnableQueries(boolean queries) {
      txtQuery.setEnabled(queries);
      for ( int i = 0; i < cmbQueryType.getItemCount(); i++ )
         ((JLabel)cmbQueryType.getItemAt(i)).setEnabled(queries);
      cmbQueryType.setEnabled(queries);
      btnQuery.setEnabled(queries);
   }

   public Admin() {
      admin = this;

      enableEvents(AWTEvent.WINDOW_EVENT_MASK);

      try {
         browser = new DBBrowser(this);

         jbInit();

         pnlGrowBox.setVisible(System.getProperty("os.name").equals("Mac OS X"));

         paneEdit.addTab("XML", imgTextView, textEditor, "Syntax Highlighted XML");
         paneEdit.addTab("Grid", imgGridView, gridEditor, "Tree Editing Grid");
         paneEdit.addTab("XSLT", imgXSLTView, xsltViewer, "XSLT Stylesheet Preview");
         paneEdit.setEnabledAt(0, false);
         paneEdit.setEnabledAt(1, false);
         nodeEditor = textEditor;

         cmbQueryType.setRenderer(JLabelListCellRenderer.getInstance());
         cmbQueryType.addItem(new JLabel("XPath (Select)", imgQryXPath, SwingConstants.LEFT));
         cmbQueryType.addItem(new JLabel("FullText (Search)", imgTextView, SwingConstants.LEFT));
         cmbQueryType.addItem(new JLabel("XSLT (Transform)", imgQryXSLT, SwingConstants.LEFT));
         cmbQueryType.addItem(new JLabel("XUpdate (Insert Before)", imgQryBefore, SwingConstants.LEFT));
         cmbQueryType.addItem(new JLabel("XUpdate (Insert After)", imgQryAfter, SwingConstants.LEFT));
         cmbQueryType.addItem(new JLabel("XUpdate (Append)", imgQryAppend, SwingConstants.LEFT));
         cmbQueryType.addItem(new JLabel("XUpdate (Update)", imgQryUpdate, SwingConstants.LEFT));
         cmbQueryType.addItem(new JLabel("XUpdate (Remove)", imgQryRemove, SwingConstants.LEFT));
         cmbQueryType.setSelectedIndex(0);

         FontMetrics fm = getFontMetrics(txtQuery.getFont());
         int height = (fm.getHeight()*13);
         txtQuery.setPreferredSize(new Dimension(1, height));

         browser.setMenu(mnuObject);

         // Center the frame
         Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
         Dimension frameSize = admin.getSize();
         if (frameSize.height > screenSize.height)
           frameSize.height = screenSize.height;
         if (frameSize.width > screenSize.width)
           frameSize.width = screenSize.width;
         admin.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);

         setEnableQueries(false);

         try {
            // Read the configuration
            File cfgDir = new File(System.getProperty(dbXML.PROP_DBXML_HOME));
            File cfgFile = new File(cfgDir, "config/admin.xml");
            cfg = new AdminConfig(cfgFile);
            cfg.load();

            xsltViewer.setSelectedIndex(cfg.getDefaultXSLTView(0));
            cmbQueryType.setSelectedIndex(cfg.getDefaultQueryType(0));

            AdminConfig.DriverConfig[] drivers = cfg.getDrivers();
            for ( int i = 0; i < drivers.length; i++ ) {
               AdminConfig.DriverConfig driver = drivers[i];
               String lbl = driver.getLabel();
               dbXMLClient client = (dbXMLClient)Class.forName(driver.getClassName()).newInstance();
               client.getProperties().putAll(driver.getProperties());
               browser.addClient(client, lbl);
            }

            AdminConfig.FileSystemConfig[] filesystems = cfg.getFileSystems();
            for ( int i = 0; i < filesystems.length; i++ ) {
               AdminConfig.FileSystemConfig filesystem = filesystems[i];
               String lbl = filesystem.getLabel();
               String dir = filesystem.getDirectory();
               if ( lbl != null && lbl.length() > 0 )
                  browser.addFileSystem(dir, lbl);
               else
                  browser.addFileSystem(dir);
            }

            showToolbar = cfg.isToolbarVisible(showToolbar);
            showExplorer = cfg.isExplorerVisible(showExplorer);
            showQuery = cfg.isQueryVisible(showQuery);
            showMessages = cfg.isMessagesVisible(showMessages);
            showStatusbar = cfg.isStatusbarVisible(showStatusbar);

            updateToolbar();
            updateExplorer();
            updateQuery();
            updateMessages();
            updateStatusbar();
         }
         catch ( Exception e ) {
            addMessage("Error Reading Configuration File");
            addMessage(e.toString());
         }
      }
      catch ( Exception e ) {
         addMessage(e.toString());
      }
      finally {
         splash.done();
         splash = null;
      }
   }

   private void jbInit() throws Exception {
      textEditor.setEnabled(false);
      imgTextView = new ImageIcon(Admin.class.getResource("components/text_view.gif"));
      imgGridView = new ImageIcon(Admin.class.getResource("components/grid_view.gif"));
      imgPlainView = new ImageIcon(Admin.class.getResource("components/plain_view.gif"));
      imgXSLTView = new ImageIcon(Admin.class.getResource("components/xslt_view.gif"));
      imgNew = new ImageIcon(Admin.class.getResource("hsNew.gif"));
      imgOpen = new ImageIcon(Admin.class.getResource("hsOpen.gif"));
      imgSave = new ImageIcon(Admin.class.getResource("hsSave.gif"));
      imgAbout = new ImageIcon(Admin.class.getResource("hsAbout.gif"));
      imgCut = new ImageIcon(Admin.class.getResource("hsCut.gif"));
      imgCopy = new ImageIcon(Admin.class.getResource("hsCopy.gif"));
      imgPaste = new ImageIcon(Admin.class.getResource("hsPaste.gif"));
      imgInsert = new ImageIcon(Admin.class.getResource("hsInsert.gif"));
      imgRemove = new ImageIcon(Admin.class.getResource("hsRemove.gif"));
      imgSearch = new ImageIcon(Admin.class.getResource("hsSearch.gif"));
      imgUndo = new ImageIcon(Admin.class.getResource("hsUndo.gif"));
      imgIcon = new ImageIcon(Admin.class.getResource("dbxml_icon.gif"));
      imgQryBefore = new ImageIcon(Admin.class.getResource("insert_before.gif"));
      imgQryAfter = new ImageIcon(Admin.class.getResource("insert_after.gif"));
      imgQryRemove = new ImageIcon(Admin.class.getResource("delete.gif"));
      imgQryAppend = new ImageIcon(Admin.class.getResource("append.gif"));
      imgQryUpdate = new ImageIcon(Admin.class.getResource("update.gif"));
      imgQryXPath = new ImageIcon(Admin.class.getResource("xpath.gif"));
      imgQryXSLT = new ImageIcon(Admin.class.getResource("xslt.gif"));
      brdTwoPixel = BorderFactory.createEmptyBorder(2, 0, 2, 0);
      setIconImage(imgIcon.getImage());
      contentPane = (JPanel)this.getContentPane();
      strut1 = Box.createHorizontalStrut(8);
      strut2 = Box.createHorizontalStrut(8);
      strut3 = Box.createHorizontalStrut(8);
      brdTitled = new TitledBorder("");
      brdQueryEdit = BorderFactory.createEmptyBorder(0, 0, 2, 0);
      contentPane.setLayout(contentPaneLayout);
      this.setSize(new Dimension(800, 600));
      this.setTitle(dbXML.Title + " Administrator");
      mnuFile.setMnemonic('F');
      mnuFile.setText("File");
      mnuFileExit.setMnemonic('X');
      mnuFileExit.setText("Exit");
      mnuFileExit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(115, java.awt.event.KeyEvent.ALT_MASK, false));
      mnuFileExit.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            fileExit_actionPerformed(e);
         }
      });
      mnuHelp.setMnemonic('H');
      mnuHelp.setText("Help");
      mnuHelpAbout.setMnemonic('A');
      mnuHelpAbout.setText("About...");
      mnuHelpAbout.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            helpAbout_actionPerformed(e);
         }
      });
      btnOpen.setIcon(imgOpen);
      btnOpen.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            fileOpen_actionPerformed(e);
         }
      });
      btnOpen.setToolTipText("Open Document");
      btnSave.setIcon(imgSave);
      btnSave.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            fileSave_actionPerformed(e);
         }
      });
      btnSave.setToolTipText("Save Document");
      btnAbout.setIcon(imgAbout);
      btnAbout.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            helpAbout_actionPerformed(e);
         }
      });
      btnAbout.setToolTipText("About");
      pnlQueryEdit.setLayout(pnlQueryEditLayout);
      pnlQueryEdit.setBorder(brdQueryEdit);
      pnlQueryEdit.setMinimumSize(new Dimension(30, 100));
      pnlQueryEdit.setPreferredSize(new Dimension(30, 150));
      paneEdit.setTabPlacement(JTabbedPane.BOTTOM);
      paneEdit.addChangeListener(new javax.swing.event.ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            paneEdit_stateChanged(e);
         }
      });
      btnNew.setToolTipText("New Document");
      btnNew.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            fileNew_actionPerformed(e);
         }
      });
      btnNew.setIcon(imgNew);
      btnCut.setToolTipText("Cut Selection");
      btnCut.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editCut_actionPerformed(e);
         }
      });
      btnCut.setIcon(imgCut);
      btnCopy.setToolTipText("Copy Selection");
      btnCopy.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editCopy_actionPerformed(e);
         }
      });
      btnCopy.setIcon(imgCopy);
      btnPaste.setToolTipText("Paste Clipboard");
      btnPaste.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editPaste_actionPerformed(e);
         }
      });
      btnPaste.setIcon(imgPaste);
      btnUndo.setToolTipText("Undo Modification");
      btnUndo.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editUndo_actionPerformed(e);
         }
      });
      btnUndo.setIcon(imgUndo);
      btnSearch.setToolTipText("Find Text");
      btnSearch.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editSearch_actionPerformed(e);
         }
      });
      btnSearch.setIcon(imgSearch);
      mnuEdit.setMnemonic('E');
      mnuEdit.setText("Edit");
      mnuEdit.addMenuListener(new javax.swing.event.MenuListener() {
         public void menuSelected(MenuEvent e) {
            mnuEdit_menuSelected(e);
         }
         public void menuDeselected(MenuEvent e) {
         }
         public void menuCanceled(MenuEvent e) {
         }
      });
      mnuEditUndo.setMnemonic('U');
      mnuEditUndo.setText("Undo");
      mnuEditUndo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(90, java.awt.event.KeyEvent.CTRL_MASK, false));
      mnuEditUndo.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editUndo_actionPerformed(e);
         }
      });
      mnuEditCut.setMnemonic('U');
      mnuEditCut.setText("Cut");
      mnuEditCut.setAccelerator(javax.swing.KeyStroke.getKeyStroke(88, java.awt.event.KeyEvent.CTRL_MASK, false));
      mnuEditCut.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editCut_actionPerformed(e);
         }
      });
      mnuEditCopy.setMnemonic('C');
      mnuEditCopy.setText("Copy");
      mnuEditCopy.setAccelerator(javax.swing.KeyStroke.getKeyStroke(67, java.awt.event.KeyEvent.CTRL_MASK, false));
      mnuEditCopy.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editCopy_actionPerformed(e);
         }
      });
      mnuEditPaste.setMnemonic('P');
      mnuEditPaste.setText("Paste");
      mnuEditPaste.setAccelerator(javax.swing.KeyStroke.getKeyStroke(86, java.awt.event.KeyEvent.CTRL_MASK, false));
      mnuEditPaste.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editPaste_actionPerformed(e);
         }
      });
      mnuEditFind.setMnemonic('F');
      mnuEditFind.setText("Find...");
      mnuEditFind.setAccelerator(javax.swing.KeyStroke.getKeyStroke(70, java.awt.event.KeyEvent.CTRL_MASK, false));
      mnuEditFind.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editSearch_actionPerformed(e);
         }
      });
      mnuEditFindNext.setMnemonic('N');
      mnuEditFindNext.setText("Find Next");
      mnuEditFindNext.setAccelerator(javax.swing.KeyStroke.getKeyStroke(114, 0, false));
      mnuEditFindNext.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editSearchNext_actionPerformed(e);
         }
      });
      mnuFilePreferences.setMnemonic('P');
      mnuFilePreferences.setText("Preferences...");
      mnuFilePreferences.setAccelerator(javax.swing.KeyStroke.getKeyStroke(80, java.awt.event.KeyEvent.CTRL_MASK, false));
      mnuFilePreferences.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            filePreferences_actionPerformed(e);
         }
      });
      mnuHelpContents.setMnemonic('C');
      mnuHelpContents.setText("Contents");
      mnuHelpContents.setAccelerator(javax.swing.KeyStroke.getKeyStroke(112, 0, false));
      mnuHelpContents.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            helpContents_actionPerformed(e);
         }
      });
      mnuObject.setText("Object");
      btnQuery.setFont(new java.awt.Font("Dialog", 0, 12));
      btnQuery.setText("Query");
      btnQuery.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            btnQuery_actionPerformed(e);
         }
      });
      cmbQueryType.setFont(new java.awt.Font("Dialog", 0, 12));
      cmbQueryType.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            cmbQueryType_actionPerformed(e);
         }
      });
      splitQuery.setOrientation(JSplitPane.VERTICAL_SPLIT);
      splitQuery.setBorder(null);
      splitQuery.setDividerSize(5);
      splitQuery.setResizeWeight(0);
      pnlQueryEditLayout.setHgap(2);
      pnlQueryEditLayout.setVgap(2);
      pnlQueryButtons.setLayout(layoutPnlQueryButtons);
      txtQuery.setLanguage(SyntaxTextArea.LANG_XML);
      statusBar.setBorder(BorderFactory.createEtchedBorder());
      statusBar.setFont(new java.awt.Font("Dialog", 0, 12));
      statusBar.setForeground(Color.black);
      statusBar.setText(" ");
      pnlStatus.setLayout(pnlStatusLayout);
      lblColName.setFont(new java.awt.Font("Dialog", 0, 12));
      lblColName.setForeground(Color.black);
      lblColName.setBorder(BorderFactory.createEtchedBorder());
      lblColName.setText(" ");
      lblDocName.setFont(new java.awt.Font("Dialog", 0, 12));
      lblDocName.setForeground(Color.black);
      lblDocName.setBorder(BorderFactory.createEtchedBorder());
      lblDocName.setText(" ");
      pnlStatusInfo.setLayout(pnlStatusInfoLayout);
      pnlStatusInfoLayout.setHgap(0);
      pnlStatusInfoLayout.setVgap(0);
      lblQueryType.setFont(new java.awt.Font("Dialog", 0, 12));
      lblQueryType.setForeground(Color.black);
      lblQueryType.setHorizontalAlignment(SwingConstants.LEFT);
      mnuView.setMnemonic('V');
      mnuView.setText("View");
      mnuViewExplorer.setMnemonic('E');
      mnuViewExplorer.setText("Explorer");
      mnuViewExplorer.setState(true);
      mnuViewExplorer.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            viewExplorer_actionPerformed(e);
         }
      });
      mnuViewQuery.setMnemonic('Q');
      mnuViewQuery.setText("Query");
      mnuViewQuery.setState(true);
      mnuViewQuery.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            viewQuery_actionPerformed(e);
         }
      });
      mnuViewMessages.setMnemonic('M');
      mnuViewMessages.setText("Messages");
      mnuViewMessages.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            viewMessages_actionPerformed(e);
         }
      });
      mnuViewToolbar.setMnemonic('T');
      mnuViewToolbar.setText("Tool Bar");
      mnuViewToolbar.setState(true);
      mnuViewToolbar.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            viewToolbar_actionPerformed(e);
         }
      });
      mnuViewStatusBar.setText("Status Bar");
      mnuViewStatusBar.setState(true);
      mnuViewStatusBar.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            viewStatusBar_actionPerformed(e);
         }
      });
      splitExplorer.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
      splitExplorer.setBorder(null);
      splitExplorer.setBottomComponent(null);
      splitExplorer.setDividerSize(5);
      splitExplorer.setResizeWeight(0);
      splitExplorer.setLeftComponent(scrollBrowser);
      splitExplorer.setRightComponent(splitQuery);
      splitMessage.setOrientation(JSplitPane.VERTICAL_SPLIT);
      splitMessage.setBorder(null);
      splitMessage.setBottomComponent(scrollMessages);
      splitMessage.setDividerSize(5);
      splitMessage.setResizeWeight(1);
      splitMessage.setTopComponent(splitExplorer);
      txtMessages.setBorder(null);
      txtMessages.setEditable(false);
      scrollBrowser.setMinimumSize(new Dimension(150, 30));
      scrollMessages.setMinimumSize(new Dimension(30, 100));
      pnlGrowBox.setMinimumSize(new Dimension(15, 10));
      pnlGrowBox.setPreferredSize(new Dimension(15, 10));
      mnuEditBeautify.setMnemonic('B');
      mnuEditBeautify.setText("Beautify");
      mnuEditBeautify.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(ActionEvent e) {
            editBeautify_actionPerformed(e);
         }
      });
      toolBar.setFloatable(false);
      mnuFile.add(mnuFilePreferences);
      mnuFile.addSeparator();
      mnuFile.add(mnuFileExit);
      mnuHelp.add(mnuHelpContents);
      mnuHelp.addSeparator();
      mnuHelp.add(mnuHelpAbout);
      mnuMain.add(mnuFile);
      mnuMain.add(mnuEdit);
      mnuMain.add(mnuObject);
      mnuMain.add(mnuView);
      mnuMain.add(mnuHelp);
      this.setJMenuBar(mnuMain);
      contentPane.add(toolBar, BorderLayout.NORTH);
      toolBar.add(btnNew, null);
      toolBar.add(btnOpen);
      toolBar.add(btnSave);
      toolBar.add(strut1, null);
      toolBar.add(btnCut, null);
      toolBar.add(btnCopy, null);
      toolBar.add(btnPaste, null);
      toolBar.add(btnUndo, null);
      toolBar.add(strut2, null);
      toolBar.add(btnSearch, null);
      toolBar.add(strut3, null);
      toolBar.add(btnAbout);
      contentPane.add(pnlStatus, BorderLayout.SOUTH);
      pnlStatus.add(pnlStatusInfo, BorderLayout.EAST);
      pnlStatusInfo.add(lblColName, null);
      pnlStatusInfo.add(lblDocName, null);
      pnlStatusInfo.add(pnlGrowBox, null);
      pnlStatus.add(statusBar, BorderLayout.CENTER);
      contentPane.add(splitMessage, BorderLayout.CENTER);
      pnlQueryEdit.add(pnlQueryButtons, BorderLayout.SOUTH);
      pnlQueryButtons.add(btnQuery, BorderLayout.EAST);
      pnlQueryButtons.add(cmbQueryType, BorderLayout.WEST);
      pnlQueryButtons.add(lblQueryType, BorderLayout.CENTER);
      pnlQueryEdit.add(txtQuery, BorderLayout.CENTER);
      splitQuery.setTopComponent(pnlQueryEdit);
      splitQuery.setBottomComponent(paneEdit);
      mnuEdit.add(mnuEditUndo);
      mnuEdit.addSeparator();
      mnuEdit.add(mnuEditCut);
      mnuEdit.add(mnuEditCopy);
      mnuEdit.add(mnuEditPaste);
      mnuEdit.addSeparator();
      mnuEdit.add(mnuEditFind);
      mnuEdit.add(mnuEditFindNext);
      mnuEdit.addSeparator();
      mnuEdit.add(mnuEditBeautify);
      scrollBrowser.getViewport().add(browser, null);
      scrollBrowser.setPreferredSize(new Dimension(250, 30));
      scrollMessages.getViewport().add(txtMessages, null);
      scrollMessages.setPreferredSize(new Dimension(30, 150));
      mnuView.add(mnuViewToolbar);
      mnuView.add(mnuViewExplorer);
      mnuView.add(mnuViewQuery);
      mnuView.add(mnuViewMessages);
      mnuView.add(mnuViewStatusBar);
   }

   protected void processWindowEvent(WindowEvent e) {
      super.processWindowEvent(e);
      if ( e.getID() == WindowEvent.WINDOW_CLOSING ) {
         fileExit_actionPerformed(null);
      }
   }

   public void fileExit_actionPerformed(ActionEvent e) {
      System.exit(0);
   }

   public void helpAbout_actionPerformed(ActionEvent e) {
      AboutDialog about = new AboutDialog(this);
      about.show();
   }

   public void fileNew_actionPerformed(ActionEvent e) {
      String newDoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
         + "<document>\n"
         + "   \n"
         + "</document>";

      DocWrapper dw = new DocWrapper(newDoc, null, null, null, true);
      editDocument(dw, true);
   }

   public void fileOpen_actionPerformed(ActionEvent e) {
      TreePath path = browser.getSelectionPath();
      if ( path == null )
         return;

      try {
         DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
         AdminNode info = (AdminNode)node.getUserObject();

         if ( info instanceof HasDocWrapper ) {
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            Stopwatch sw = new Stopwatch("Document Retrieval", true);
            DocWrapper dw = ((HasDocWrapper)info).getDocWrapper();
            sw.stop();
            statusBar.setText(sw.toString());
            editDocument(dw);
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
         }
      }
      catch ( Exception ex ) {
         addMessage(ex.toString());
      }
   }

   public void editDocument(DocWrapper doc) {
      editDocument(doc, false);
   }

   public void editDocument(DocWrapper doc, boolean newDocument) {
      TabbedNodeEditor ne = (TabbedNodeEditor)paneEdit.getSelectedComponent();
      if ( ne.isModified() ) {
         String title;
         StringBuffer sb = new StringBuffer();
         sb.append("The current Document has been modified.\n");
         if ( newDocument ) {
            title = "Confirm New Document";
            sb.append("Would you like to save it before creating\n");
         }
         else {
            title = "Confirm Load";
            sb.append("Would you like to save it before loading\n");
         }
         sb.append("the new Document?");

         int res = JOptionPane.showConfirmDialog(this, sb.toString(), title, JOptionPane.YES_NO_CANCEL_OPTION);
         switch ( res ) {
            case JOptionPane.YES_OPTION:
               if ( !saveDocument() )
                  return;
               else
                  break;

            case JOptionPane.CANCEL_OPTION:
               return;
         }
      }

      this.newDocument = newDocument;
      this.doc = doc;
      this.readOnly = !doc.isStorable();

      textEditor.setEnabled(true);
      textEditor.setLanguage(doc.getLanguage());

      boolean sys = false;
      try {
         CollectionClient c = doc.col.getParentCollection();
         while ( !sys && c != null ) {
            sys = c.getName().equals("system");
            if ( !sys )
               c = c.getParentCollection();
         }
      }
      catch ( Exception e ) {
         // No Parent or NullPointer, either way, it ain't system
      }

      if ( sys )
         gridEditor.setResourceMap(SystemResMap);
      else
         gridEditor.setResourceMap(DefaultResMap);

      gridEditor.setShowRootElement(true);
      gridEditor.setExpanded(true);

      String colName = doc.getLocation();
      String docName = doc.getName();

      StringBuffer sb = new StringBuffer();
      sb.append(dbXML.Title + " Administrator - ");
      if ( colName != null ) {
         lblColName.setText(colName);
         sb.append(colName);
         sb.append("/");
      }
      else
         lblColName.setText(" ");

      if ( docName != null ) {
         lblDocName.setText(docName);
         sb.append(docName);
      }
      else {
         lblDocName.setText("untitled.xml");
         sb.append("untitled.xml");
      }
      this.setTitle(sb.toString());

      ignoreChange = true;
      if ( doc.getLanguage().equals(SyntaxTextArea.LANG_XML) ) {
         for ( int i = 0; i < paneEdit.getTabCount(); i++ )
            paneEdit.setEnabledAt(i, true);

         if ( cfg.isAutoBeautify(false) ) {
            try {
               Document d = doc.getDocument();
               String newText = TextWriter.toPrettyString(d).trim();
               d = DOMHelper.parseText(newText);
               doc.setDocument(d);
            }
            catch ( Exception e ) {
               addMessage(e.getMessage());
            }
         }

         ne.setDocWrapper(doc);
         ne.activate(readOnly);
         nodeEditor = ne;
         ((JComponent)paneEdit.getSelectedComponent()).requestFocus();
      }
      else {
         for ( int i = 0; i < paneEdit.getTabCount(); i++ )
            paneEdit.setEnabledAt(i, i == 0);

         paneEdit.setSelectedComponent(textEditor);
         ne = textEditor;
         ne.setDocWrapper(doc);
         ne.activate(readOnly);
         nodeEditor = ne;
         textEditor.requestFocus();
      }
      ignoreChange = false;
   }

   private boolean saveDocument() {
      if ( doc != null && doc.isStorable() ) {
         if ( newDocument )
            return storeNewDocument();
         else
            return storeExistingDocument();
      }
      return false;
   }

   private boolean storeNewDocument() {
      AdminNode[] nodes = null;
      HasStorage store = null;
      AdminNode refresh = null;

      TreePath path = browser.getSelectionPath();
      Object[] components = null;
      if ( path != null ) {
         components = path.getPath();
         java.util.List list = new ArrayList();
         for ( int i = 0; i < components.length; i++ ) {
            DefaultMutableTreeNode n = (DefaultMutableTreeNode)components[i];
            list.add(n.getUserObject());
         }
         nodes = (AdminNode[])list.toArray(EmptyAdminNodes);

         for ( int i = nodes.length-1; store == null && i >= 0; i-- ) {
            if ( nodes[i] instanceof HasStorage ) {
               store = (HasStorage)nodes[i];
               refresh = store.getRefreshTarget();
            }
         }
      }

      if ( store == null ) {
         StringBuffer sb = new StringBuffer();
         sb.append("There is currently no container selected.\n");
         sb.append("Please select a container to save the Document.");

         JOptionPane.showMessageDialog(this, sb.toString(), "Save Document", JOptionPane.OK_OPTION);
         return false;
      }

      StringBuffer sb = new StringBuffer();
      sb.append("Please type a name for your new Document.");
      String name = JOptionPane.showInputDialog(this, sb.toString(), "New Document", JOptionPane.OK_CANCEL_OPTION);
      if ( name != null && name.length() > 0 )
         doc.setName(name);
      else
         return false;

      Stopwatch sw = new Stopwatch("Document Storage", true);
      TabbedNodeEditor ne = (TabbedNodeEditor)paneEdit.getSelectedComponent();
      if ( ne.deactivate() ) {
         store.storeDocWrapper(doc);
         ne.activate(readOnly);
         nodeEditor = ne;
      }
      sw.stop();
      statusBar.setText(sw.toString());

      DefaultMutableTreeNode refreshNode = null;
      if ( nodes[nodes.length-1] == refresh )
         refreshNode = (DefaultMutableTreeNode)components[nodes.length-1];
      else {
         DefaultMutableTreeNode node = (DefaultMutableTreeNode)components[nodes.length-1];
         for ( int i = 0; i < node.getChildCount(); i++ ) {
            DefaultMutableTreeNode n = (DefaultMutableTreeNode)node.getChildAt(i);
            if ( n.getUserObject() == refresh )
               refreshNode = n;
         }
      }
      if ( refreshNode != null ) {
         TreePath p = new TreePath(refreshNode.getPath());
         browser.collapsePath(p);
         browser.expandPath(p);
      }

      newDocument = false;
      return true;
   }

   private boolean storeExistingDocument() {
      Stopwatch sw = new Stopwatch("Document Storage", true);
      TabbedNodeEditor ne = (TabbedNodeEditor)paneEdit.getSelectedComponent();
      if ( ne.deactivate() ) {
         doc.store();
         ne.activate(readOnly);
         nodeEditor = ne;
      }
      sw.stop();
      statusBar.setText(sw.toString());
      return true;
   }

   public void fileSave_actionPerformed(ActionEvent e) {
      saveDocument();
   }

   public void fileConnect_actionPerformed(ActionEvent e) {
      browser.getAdminRoot().menuAction(RootNode.ACTION_CONNECT);
   }

   void mnuEdit_menuSelected(MenuEvent e) {
      mnuEditCut.setEnabled(nodeEditor.isCutEnabled());
      mnuEditCopy.setEnabled(nodeEditor.isCopyEnabled());
      mnuEditPaste.setEnabled(nodeEditor.isPasteEnabled());
      mnuEditUndo.setEnabled(nodeEditor.isUndoEnabled());
      mnuEditBeautify.setEnabled(nodeEditor.isBeautifyEnabled());
   }

   public void editCut_actionPerformed(ActionEvent e) {
      if ( nodeEditor.isCutEnabled() )
         nodeEditor.cut();
   }

   public void editCopy_actionPerformed(ActionEvent e) {
      if ( nodeEditor.isCopyEnabled() )
         nodeEditor.copy();
   }

   public void editPaste_actionPerformed(ActionEvent e) {
      if ( nodeEditor.isPasteEnabled() )
         nodeEditor.paste();
   }

   public void editUndo_actionPerformed(ActionEvent e) {
      if ( nodeEditor.isUndoEnabled() )
         nodeEditor.undo();
   }

   public void editSearch_actionPerformed(ActionEvent e) {
      nodeEditor.find();
   }

   public void editSearchNext_actionPerformed(ActionEvent e) {
      nodeEditor.findNext();
   }

   public void editBeautify_actionPerformed(ActionEvent e) {
      textEditor.beautify();
   }

   public void filePreferences_actionPerformed(ActionEvent e) {
      PreferencesDialog prefs = new PreferencesDialog(this);
      prefs.show();
   }

   public void helpContents_actionPerformed(ActionEvent e) {

   }

   public void viewToolbar_actionPerformed(ActionEvent e) {
      showToolbar = !showToolbar;
      updateToolbar();

      try {
         cfg.setToolbarVisible(showToolbar);
         cfg.save();
      }
      catch ( IOException ex ) {
      }
   }

   public void viewExplorer_actionPerformed(ActionEvent e) {
      showExplorer = !showExplorer;
      updateExplorer();

      try {
         cfg.setExplorerVisible(showExplorer);
         cfg.save();
      }
      catch ( IOException ex ) {
      }
   }

   public void viewQuery_actionPerformed(ActionEvent e) {
      showQuery = !showQuery;
      updateQuery();

      try {
         cfg.setQueryVisible(showQuery);
         cfg.save();
      }
      catch ( IOException ex ) {
      }
   }

   public void viewMessages_actionPerformed(ActionEvent e) {
      showMessages = !showMessages;
      updateMessages();

      try {
         cfg.setMessagesVisible(showMessages);
         cfg.save();
      }
      catch ( IOException ex ) {
      }
   }

   public void viewStatusBar_actionPerformed(ActionEvent e) {
      showStatusbar = !showStatusbar;
      updateStatusbar();

      try {
         cfg.setStatusbarVisible(showStatusbar);
         cfg.save();
      }
      catch ( IOException ex ) {
      }
   }

   public void updateToolbar() {
      mnuViewToolbar.setSelected(showToolbar);
      toolBar.setVisible(showToolbar);
   }

   public void updateExplorer() {
      if ( showExplorer ) {
         splitExplorer.getLeftComponent().setVisible(true);
         mnuViewExplorer.setState(true);
         splitExplorer.setDividerSize(5);

         int loc = locExplorer;
         if ( loc == -1 )
            loc = splitExplorer.getLeftComponent().getPreferredSize().width;
         splitExplorer.setDividerLocation(loc);
      }
      else {
         locExplorer = splitExplorer.getDividerLocation();
         splitExplorer.getLeftComponent().setVisible(false);
         mnuViewExplorer.setState(false);
         splitExplorer.setDividerSize(0);
      }
   }

   public void updateQuery() {
      if ( showQuery ) {
         splitQuery.getTopComponent().setVisible(true);
         mnuViewQuery.setState(true);
         splitQuery.setDividerSize(5);

         int loc = locQuery;
         if ( loc == -1 )
            loc = splitQuery.getTopComponent().getPreferredSize().height;

         splitQuery.setDividerLocation(loc);
      }
      else {
         locQuery = splitQuery.getDividerLocation();

         splitQuery.getTopComponent().setVisible(false);
         mnuViewQuery.setState(false);
         splitQuery.setDividerSize(0);
      }
   }

   public void updateMessages() {
      if ( showMessages ) {
         splitMessage.getBottomComponent().setVisible(true);
         mnuViewMessages.setState(true);
         splitMessage.setDividerSize(5);

         int loc = locMessage;
         if ( loc == -1 ) {
            loc = splitMessage.getBottomComponent().getPreferredSize().height;

            int height = splitMessage.getSize().height;
            if ( height > 0 )
               splitMessage.setDividerLocation(height-loc);
         }
         else
            splitMessage.setDividerLocation(loc);
      }
      else {
         locMessage = splitMessage.getDividerLocation();

         splitMessage.getBottomComponent().setVisible(false);
         mnuViewMessages.setState(false);
         splitMessage.setDividerSize(0);
      }
   }

   public void updateStatusbar() {
      mnuViewStatusBar.setSelected(showStatusbar);
      pnlStatus.setVisible(showStatusbar);
   }

   public void cmbQueryType_actionPerformed(ActionEvent e) {
      String opName = null;
      String qString = null;

      if ( oldQueryTextIdx != -1 )
         queryText[oldQueryTextIdx] = txtQuery.getText();

      int idx = cmbQueryType.getSelectedIndex();
      if ( queryText[idx] == null ) {
         switch ( idx ) {
            case 0:
               qString = "<dbxml:xpath xmlns:dbxml=\""+Query.NSURI+"\">\n"
                  + "   <!-- The above dbxml:xpath element can\n"
                  + "        be used for namespace definitions -->\n"
                  + "   /*\n"
                  + "</dbxml:xpath>";
               break;

            case 1:
               qString = "<dbxml:fulltext xmlns:dbxml=\""+Query.NSURI+"\"\n"
                  + "                xpath=\"\">\n"
                  + "   <!-- The above dbxml:fulltext element can\n"
                  + "        be used for namespace definitions.  Use\n"
                  + "        the name attribute in the below select\n"
                  + "        element to specify a document element -->\n"
                  + "   <select name=\"\">\n"
                  + "      \n"
                  + "   </select>\n"
                  + "</dbxml:fulltext>";
               break;
            case 2:
               qString = "<dbxml:xslt xmlns:dbxml=\""+Query.NSURI+"\">\n"
                  + "   <dbxml:source xpath=\"\" document=\"\">\n"
                  + "      <!-- optionally source XML -->\n"
                  + "   </dbxml:source>\n"
                  + "   <dbxml:params>\n"
                  + "      <!-- <param name=\"\" value=\"\"> -->\n"
                  + "   </dbxml:params>\n"
                  + "   <dbxml:stylesheet document=\"\">\n"
                  + "      <!-- optionally a stylesheet -->\n"
                  + "   </dbxml:stylesheet>\n"
                  + "</dbxml:xslt>";
               break;

            case 3:
               opName = "insert-before";
               break;

            case 4:
               opName = "insert-after";
               break;

            case 5:
               qString = "<xu:modifications version=\"1.0\" xmlns:xu=\"http://www.xmldb.org/xupdate\">\n"
                  + "   <xu:append select=\"\" child=\"last()\">\n"
                  + "      <!-- Add append nodes here -->\n"
                  + "      \n"
                  + "   </xu:append>\n"
                  + "</xu:modifications>";
               break;

            case 6:
               opName = "update";
               break;

            case 7:
               qString = "<xu:modifications version=\"1.0\" xmlns:xu=\"http://www.xmldb.org/xupdate\">\n"
                  + "   <xu:remove select=\"\" />\n"
                  + "</xu:modifications>";
               break;
         }

         if ( opName != null && qString == null )
            qString = "<xu:modifications version=\"1.0\" xmlns:xu=\"http://www.xmldb.org/xupdate\">\n"
               + "   <xu:" + opName + " select=\"\">\n"
               + "      <!-- Add " + opName + " nodes here -->\n"
               + "      \n"
               + "   </xu:" + opName + ">\n"
               + "</xu:modifications>";

         queryText[idx] = qString;
      }
      else
         qString = queryText[idx];

      oldQueryTextIdx = idx;

      if ( qString != null ) {
         txtQuery.setText(qString);
         txtQuery.setCaretPosition(0);
      }

      txtQuery.requestFocus();
   }

   public void btnQuery_actionPerformed(ActionEvent e) {
      TreePath path = browser.getSelectionPath();
      if ( path == null )
         return;

      String query = txtQuery.getText().trim();

      if ( query.length() == 0 )
         return;

      try {
         DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
         AdminNode info = (AdminNode)node.getUserObject();

         if ( info instanceof HasCollection && ((HasCollection)info).getCollection() != null ) {
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            CollectionClient col = ((HasCollection)info).getCollection();
            Stopwatch sw = new Stopwatch("Query Results", true);
            String style;
            switch ( cmbQueryType.getSelectedIndex() ) {
               case 0:  style = XPathQueryResolver.STYLE_XPATH;       break;
               case 1:  style = FullTextQueryResolver.STYLE_FULLTEXT; break;
               case 2:  style = XSLTQueryResolver.STYLE_XSLT;         break;
               default: style = XUpdateQueryResolver.STYLE_XUPDATE;   break;
            }
            ResultSetClient rs = col.queryCollection(style, query, cfg.getNamespaceMap());

            sw.stop();
            statusBar.setText(sw.toString());

            Document doc = DOMHelper.newDocument();
            Element root = doc.createElementNS(Query.NSURI, Query.PREFIX+":"+ResultSetWrapper.RESULTS);
            String colName = rs.getCollection().getCanonicalName();
            root.setAttribute("xmlns:"+Query.PREFIX, Query.NSURI);
            root.setAttribute(ResultSetWrapper.COL, colName);
            int count = rs.getCount();
            if ( count != -1 )
               root.setAttribute(ResultSetWrapper.COUNT, Integer.toString(count));
            doc.appendChild(root);
            root.appendChild(doc.createTextNode("\n"));

            while ( rs.next() ) {
               Node n = rs.getResult();
               Element result = doc.createElementNS(Query.NSURI, Query.PREFIX+":"+ResultSetWrapper.RESULT);
               result.appendChild(doc.createTextNode("\n"));
               CollectionClient rc = rs.getResultCollection();
               String rsColName = rc.getCanonicalName();
               if ( !rsColName.equals(colName) )
                  result.setAttribute(ResultSetWrapper.COL, rsColName);
               String key = rs.getResultKey();
               if ( key != null && key.length() > 0 )
                  result.setAttribute(ResultSetWrapper.KEY, key);
               result.appendChild(doc.importNode(n, true));
               result.appendChild(doc.createTextNode("\n"));
               root.appendChild(result);
               root.appendChild(doc.createTextNode("\n"));
            }

            JLabel lbl = (JLabel)cmbQueryType.getSelectedItem();

            DocWrapper dw = new DocWrapper(doc, col, null, lbl.getText(), false);
            editDocument(dw);
         }
      }
      catch ( Exception ex ) {
         addMessage(ex.toString());
      }
      finally {
         setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      }
   }

   public void paneEdit_stateChanged(ChangeEvent e) {
      if ( doc == null || ignoreChange )
         return;
      TabbedNodeEditor ne = nodeEditor;
      if ( ne.deactivate() ) {
         boolean mod = ne.isModified();
         DocWrapper d = ne.getDocWrapper();
         ne = (TabbedNodeEditor)paneEdit.getSelectedComponent();
         ne.setDocWrapper(d);
         if ( mod )
            ne.reset();
         ne.activate(readOnly);
         nodeEditor = ne;
      }
      else
         paneEdit.setSelectedComponent((JComponent)ne);
      ((JComponent)paneEdit.getSelectedComponent()).requestFocus();
   }

   public void refreshMenuBar() {
      mnuMain.revalidate();
      mnuMain.repaint();
   }

   public void setStatus(String status) {
      statusBar.setText(status);
   }

   public void addClientConfig(dbXMLClient client, String label) {
      try {
         AdminConfig.DriverConfig driver = cfg.newDriverConfig();
         driver.setLabel(label);
         driver.setClassName(client.getClass().getName());
         driver.getProperties().putAll(client.getProperties());
         cfg.addDriverConfig(driver);
         cfg.save();
      }
      catch ( Exception e ) {
         addMessage(e.toString());
      }
   }

   public void addFileSystem(String path, String label) {
      try {
         AdminConfig.FileSystemConfig fileSystem = cfg.newFileSystemConfig();
         fileSystem.setDirectory(path);
         fileSystem.setLabel(label);
         cfg.addFileSystem(fileSystem);
         cfg.save();
      }
      catch ( Exception e ) {
         addMessage(e.toString());
      }
   }

   public void addMessage(String message) {
      if ( !showMessages ) {
         showMessages = true;
         updateMessages();
      }
      StringBuffer sb = new StringBuffer(txtMessages.getText());
      if ( sb.length() > 0 )
         sb.append('\n');
      sb.append(message);
      String newText = sb.toString();
      txtMessages.setText(newText);
      txtMessages.setSelectionStart(newText.length());
      txtMessages.setSelectionEnd(newText.length());
   }
}


