//------------------------------------------------------------------------------ // Desc: XEdit // // Tabs: 3 // // Copyright (c) 2003-2006 Novell, Inc. All Rights Reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of version 2 of the GNU General Public // License as published by the Free Software Foundation. // // 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, contact Novell, Inc. // // To contact Novell about this file by physical or electronic mail, // you may find current contact information at www.novell.com // // $Id: XEdit.java 3120 2006-01-19 13:41:12 -0700 (Thu, 19 Jan 2006) dsanders $ //------------------------------------------------------------------------------ package xedit; import xflaim.*; import java.awt.*; import java.awt.event.*; import java.io.File; import java.util.Vector; import javax.swing.*; /** * To change the template for this generated type comment go to * Window->Preferences->Java->Code Generation->Code and Comments */ public class XEdit extends JFrame implements Runnable, ActionListener, MouseListener, KeyListener { // Package members DbSystem m_dbSystem; Db m_jDb; // Private member variables. private JPanel m_mainDisplay; private JPanel m_mainPanel; private Status m_status; private String m_sDatabaseName; private String m_sDirectory; private Vector m_vDocList; private Vector m_vNodeList; private int m_iExpandedRow; private int m_iLastNode; private final int FIRST_NODE = 0; private final int LAST_NODE = 31; private final int NO_NODES = -1; private NodePanel m_selected; private boolean m_bDocList = false; private int m_iCollection; private Document m_doc; private XEdit m_parent = null; private JPopupMenu m_popup = null; private boolean m_bMustExit = false; /** * Basic constructor * @param title */ XEdit( String title) { super(title); init(); } /** * Collection List constructor * @param parent * @param title * @param jDb * @param iCollection * @param doc */ XEdit( XEdit parent, String title, Db jDb, int iCollection, Document doc) { super(title); m_bDocList = true; m_parent = parent; init(); m_iCollection = iCollection; m_doc = doc; m_jDb = jDb; if (!showDocumentList()) { JOptionPane.showMessageDialog( this, "Collection contains no documents", "Empty Collection", JOptionPane.INFORMATION_MESSAGE); m_bMustExit = true; } } /*------------------------------------------------------------------------- * Desc: Method to execute the common initialization tasks. *-----------------------------------------------------------------------*/ private void init() { setSize(660, 625); this.setResizable(false); this.addKeyListener(this); setDefaultCloseOperation(EXIT_ON_CLOSE); m_sDatabaseName = null; m_sDirectory = System.getProperty("user.dir"); m_selected = null; // Create a dbSystem object. try { m_dbSystem = new DbSystem(); } catch (XFlaimException e) { e.printStackTrace(); System.exit(0); } // Initialize the jDb to null; m_jDb = null; // Create the main panel that will hold everything else. m_mainPanel = new JPanel(); // Set the layout manager. m_mainPanel.setLayout(new BorderLayout()); // Create the menu and add it to the panel if (!m_bDocList) { JMenuBar menuBar = makeMainMenu(); m_mainPanel.add("North", menuBar); } // Create the status bar and add it to the panel JLabel statusBar = new JLabel((m_bDocList ? "Document List" : "No Database")); m_mainPanel.add("South", statusBar); // New Status object to track our status. m_status = new Status(statusBar); // Create the panel to display the documents and the scrollable panel and add them to the // main panel. m_mainDisplay = new JPanel(); m_mainDisplay.setLayout(new GridLayout(32, 1)); JScrollPane scrollPane = new JScrollPane(m_mainDisplay); scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); m_mainPanel.add("Center", scrollPane); m_vDocList = new Vector(); m_vNodeList = new Vector(); // Fill up the display with blank panels. for (int i = FIRST_NODE; i <= LAST_NODE; i++) { NodePanel np = new NodePanel(this, i); m_mainDisplay.add(np); m_vNodeList.addElement(np); } m_iLastNode = NO_NODES; m_status.m_iCurrentNode = NO_NODES; m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); // Make it all stick together... setContentPane(m_mainPanel); } /*========================================================================= * Desc: Method to return the size (Dimension) of the main display panel. *=======================================================================*/ public Dimension getSizeOfDisplay() { return m_mainDisplay.getSize(); } /*========================================================================= * Desc: Method to handle the events from the menu. *=======================================================================*/ public void actionPerformed(ActionEvent e) { JMenuItem source = (JMenuItem) (e.getSource()); String label = source.getText(); // Are we exiting? if (label.equals("Exit")) { System.exit(0); } else if (label.equals("Open")) { openDatabase(); } else if (label.equals("New")) { createDatabase(); } else if (label.equals("Close")) { closeDatabase(); } else if (label.equals("Remove")) { removeDatabase(); } else if (label.equals("First Document")) { getFirstDocument(); } else if (label.equals("Open Document")) { openDocument(); } else if (label.equals("Create Document")) { createDocument(m_selected); } else if (label.equals("Close Document")) { if (m_popup != null) { NodePanel np = m_selected; closeDocument(np); } else { closeDocument(); } } else if (label.equals("Import Document(s)")) { importDocument(); } else if (label.equals("Collapse Node")) { NodePanel np = m_selected; if (np.isExpanded()) { collapseNode(np); } } else if (label.equals("Expand Node")) { NodePanel np = m_selected; if (!np.isExpanded()) { expandNode(np, true); } } else if (label.equals("Delete Node")) { deleteNode(m_selected); } else if (label.equals("Delete Attribute")) { deleteAttribute(m_selected); } else if (label.equals("Delete Annotation")) { deleteAnnotation(m_selected); } else if (label.equals("Edit Value")) { editValue(m_selected); } else if (label.equals("Edit Attribute")) { editAttribute(m_selected); } else if (label.equals("Edit Annotation")) { editAnnotation(m_selected); } else if (label.equals("Add Node")) { createNode(m_selected); } else if (label.equals("Begin Transaction")) { beginTransaction(); } else if (label.equals("Commit Transaction")) { commitTransaction(); } else if (label.equals("Abort Transaction")) { abortTransaction(); } // If the popup menu is enabled, let's get rid of it. if (m_popup != null) { m_popup = null; } } /** * @param np */ private void deleteAnnotation( NodePanel np) { DOMNode jNode = null; DOMNode jAnnot = null; boolean bTransBegun = false; String sMessage; try { jNode = m_jDb.getNode(np.getCollection(), np.getNodeId(), null); if (!jNode.hasAnnotation()) { return; } jAnnot = jNode.getAnnotation(jAnnot); sMessage = new String("Delete annotation: " + jAnnot.getString()); if (JOptionPane.showConfirmDialog( this, sMessage) == JOptionPane.OK_OPTION) { // Begin a transaction if (!m_status.getTransaction()) { m_jDb.transBegin(TransactionType.UPDATE_TRANS, 0, 0); bTransBegun = true; } // Delete the node. jAnnot.deleteNode(); // Commit if (bTransBegun) { m_jDb.transCommit(); bTransBegun = false; } // Refresh the current row if (np.isExpanded() && np.isClosing()) { collapseNode(np); expandNode(m_selected, true); } else { np.buildLabel(jNode, np.isExpanded(), np.isClosing(), false); } } } catch(XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } finally { if (bTransBegun) { try { m_jDb.transAbort(); } catch (XFlaimException ex) { // ignore this one. } } } } /** * @param m_selected */ private void deleteAttribute( NodePanel np) { DOMNode jNode = null; DOMNode jAttr = null; boolean bTransBegun = false; String sMessage; try { Attribute attr = new Attribute("Empty", -1); jNode = m_jDb.getNode(np.getCollection(), np.getNodeId(), jNode); AttributeSelector AS = new AttributeSelector(this, jNode, attr); AS.dispose(); if (attr.m_lNodeId == -1) { return; // Cancelled } jAttr = m_jDb.getNode(np.getCollection(), attr.m_lNodeId, jAttr); sMessage = new String("Delete attribute: <" + jAttr.getLocalName() + "> ?"); if (JOptionPane.showConfirmDialog( this, sMessage) == JOptionPane.OK_OPTION) { // See if we need to begin an update transaction if (!m_status.getTransaction()) { m_jDb.transBegin( TransactionType.UPDATE_TRANS, 0, 0); bTransBegun = true; } jAttr.deleteNode(); if (bTransBegun) { m_jDb.transCommit(); } // Update the display. if (np.isExpanded() && np.isClosing()) { collapseNode(np); expandNode(m_selected, true); } else { np.buildLabel(jNode, np.isExpanded(), np.isClosing(), false); } } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); if (bTransBegun) { try { m_jDb.transAbort(); } catch (XFlaimException ex) { // Don't do anything here. } } } } private void editValue( NodePanel np) { DOMNode jNode = null; boolean bTransBegun = false; String sValue; if (!m_status.getDatabaseOpen()) { JOptionPane.showMessageDialog( this, "No open database", "Command Error", JOptionPane.INFORMATION_MESSAGE); return; } try { jNode = m_jDb.getNode(np.getCollection(), np.getNodeId(), jNode); sValue = jNode.getString(); NodeValue nv = new NodeValue(sValue); EditValueDialog valueDialog = new EditValueDialog("Edit Node Value", this, nv); valueDialog.dispose(); if (!sValue.equals(nv.getValue())) { // See if we need to begin an update transaction if (!m_status.getTransaction()) { m_jDb.transBegin( TransactionType.UPDATE_TRANS, 0, 0); bTransBegun = true; } jNode.setString(nv.getValue()); if (bTransBegun) { m_jDb.transCommit(); } // Update the display. if (np.isExpanded() && np.isClosing()) { collapseNode(np); expandNode(m_selected, true); } else { np.buildLabel(jNode, np.isExpanded(), np.isClosing(), false); } } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); if (bTransBegun) { try { m_jDb.transAbort(); } catch (XFlaimException ex) { // Don't do anything here. } } } } private void editAnnotation( NodePanel np) { DOMNode jNode = null; DOMNode jAnnot = null; boolean bTransBegun = false; String sValue; if (!m_status.getDatabaseOpen()) { JOptionPane.showMessageDialog( this, "No open database", "Command Error", JOptionPane.INFORMATION_MESSAGE); return; } try { jNode = m_jDb.getNode(np.getCollection(), np.getNodeId(), jNode); jAnnot = jNode.getAnnotation(jAnnot); sValue = jAnnot.getString(); NodeValue nv = new NodeValue(sValue); EditValueDialog valueDialog = new EditValueDialog("Edit Annotation Value", this, nv); valueDialog.dispose(); if (!sValue.equals(nv.getValue())) { // See if we need to begin an update transaction if (!m_status.getTransaction()) { m_jDb.transBegin( TransactionType.UPDATE_TRANS, 0, 0); bTransBegun = true; } jAnnot.setString(nv.getValue()); if (bTransBegun) { m_jDb.transCommit(); } // Update the display. if (np.isExpanded() && np.isClosing()) { collapseNode(np); expandNode(m_selected, true); } else { np.buildLabel(jNode, np.isExpanded(), np.isClosing(), false); } } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); if (bTransBegun) { try { m_jDb.transAbort(); } catch (XFlaimException ex) { // Don't do anything here. } } } } private void editAttribute( NodePanel np) { DOMNode jNode = null; DOMNode jAttr = null; boolean bTransBegun = false; String sValue; if (!m_status.getDatabaseOpen()) { JOptionPane.showMessageDialog( this, "No open database", "Command Error", JOptionPane.INFORMATION_MESSAGE); return; } try { Attribute attr = new Attribute("Empty", -1); jNode = m_jDb.getNode(np.getCollection(), np.getNodeId(), jNode); AttributeSelector AS = new AttributeSelector(this, jNode, attr); AS.dispose(); if (attr.m_lNodeId == -1) { return; // Cancelled } jAttr = m_jDb.getNode(np.getCollection(), attr.m_lNodeId, jAttr); sValue = jAttr.getString(); NodeValue nv = new NodeValue(sValue); EditValueDialog valueDialog = new EditValueDialog("Edit Attribute Value", this, nv); valueDialog.dispose(); if (!sValue.equals(nv.getValue())) { // See if we need to begin an update transaction if (!m_status.getTransaction()) { m_jDb.transBegin( TransactionType.UPDATE_TRANS, 0, 0); bTransBegun = true; } jAttr.setString(nv.getValue()); if (bTransBegun) { m_jDb.transCommit(); } // Update the display. if (np.isExpanded() && np.isClosing()) { collapseNode(np); expandNode(m_selected, true); } else { np.buildLabel(jNode, np.isExpanded(), np.isClosing(), false); } } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); if (bTransBegun) { try { m_jDb.transAbort(); } catch (XFlaimException ex) { // Don't do anything here. } } } } /** * @param m_selected */ private void createNode( NodePanel np) { if (!m_status.getDatabaseOpen()) { JOptionPane.showMessageDialog( this, "No open database", "Command Error", JOptionPane.INFORMATION_MESSAGE); return; } try { // Need to get the collection. long lNodeId = 0; int iCollection = 0; if (np != null) { lNodeId = np.getNodeId(); iCollection = np.getCollection(); } if (iCollection > 0) { NodeDialog nd = new NodeDialog( this, m_dbSystem, m_status.getDatabasePath(), lNodeId, iCollection); GraphicsConfiguration gc = nd.getGraphicsConfiguration(); Rectangle bounds = gc.getBounds(); int iHeight = nd.getHeight(); int iWidth = nd.getWidth(); nd.setLocation(Math.max(0, (bounds.width - iWidth)/2), Math.max(0, (bounds.height - iHeight)/2)); Thread t = new Thread((Runnable)nd); t.start(); } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Failed to create dialog: " + e.getMessage(), "Exception occurred", JOptionPane.ERROR_MESSAGE); } } /** * */ private void createDocument( NodePanel np) { if (!m_status.getDatabaseOpen()) { JOptionPane.showMessageDialog( this, "No open database", "Command Error", JOptionPane.INFORMATION_MESSAGE); return; } try { // Need to get the collection. int iCollection = selectCollection(); if (iCollection > 0) { long lNodeId = 0; if (np != null) { lNodeId = np.getNodeId(); } NodeDialog nd = new NodeDialog( this, m_dbSystem, m_status.getDatabasePath(), lNodeId, iCollection); GraphicsConfiguration gc = nd.getGraphicsConfiguration(); Rectangle bounds = gc.getBounds(); int iHeight = nd.getHeight(); int iWidth = nd.getWidth(); nd.setLocation(Math.max(0, (bounds.width - iWidth)/2), Math.max(0, (bounds.height - iHeight)/2)); Thread t = new Thread((Runnable)nd); t.start(); } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Failed to create dialog: " + e.getMessage(), "Exception occurred", JOptionPane.ERROR_MESSAGE); } } /** * */ private void beginTransaction() { if (m_status.getTransaction()) { JOptionPane.showMessageDialog( this, "Update transaction already in progress", "Transaction Error", JOptionPane.INFORMATION_MESSAGE); return; } try { if (m_status.getDatabaseOpen()) { m_jDb.transBegin(TransactionType.UPDATE_TRANS, 0, 0); m_status.setTransaction(true); } else { JOptionPane.showMessageDialog( this, "Cannot begin transaction - no open database.", "Incomplete Operation", JOptionPane.INFORMATION_MESSAGE); } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } /** * */ private void commitTransaction() { if (!m_status.getTransaction()) { JOptionPane.showMessageDialog( this, "No update transaction in progress", "Transaction Error", JOptionPane.INFORMATION_MESSAGE); return; } try { if (m_status.getDatabaseOpen()) { m_jDb.transCommit(); m_status.setTransaction(false); } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } /** * */ private void abortTransaction() { if (!m_status.getTransaction()) { JOptionPane.showMessageDialog( this, "No update transaction in progress", "Transaction Error", JOptionPane.INFORMATION_MESSAGE); return; } try { if (m_status.getDatabaseOpen()) { m_jDb.transAbort(); m_status.setTransaction(false); } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } /*========================================================================= * Desc: constructs the main menu for the application. *=======================================================================*/ private JMenuBar makeMainMenu() { JMenuBar menuBar = null; JMenu fileMenu = null; JMenu docMenu = null; JMenu transMenu = null; menuBar = new JMenuBar(); // Create the main menu. menuBar = new JMenuBar(); // Create the File menu fileMenu = new JMenu("File"); fileMenu.setMnemonic(KeyEvent.VK_F); // Add the file Menu to the menu bar menuBar.add(fileMenu); /*------------------------ File menu ---------------------------------*/ // Create a few items to add to the file menu JMenuItem menuItem = new JMenuItem("Open"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK)); menuItem.setMnemonic(KeyEvent.VK_O); menuItem.addActionListener(this); fileMenu.add(menuItem); menuItem = new JMenuItem("Close"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.ALT_MASK)); menuItem.setMnemonic(KeyEvent.VK_C); menuItem.addActionListener(this); fileMenu.add(menuItem); menuItem = new JMenuItem("New"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.ALT_MASK)); menuItem.setMnemonic(KeyEvent.VK_N); menuItem.addActionListener(this); fileMenu.add(menuItem); fileMenu.addSeparator(); menuItem = new JMenuItem("Remove"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK)); menuItem.setMnemonic(KeyEvent.VK_R); menuItem.addActionListener(this); fileMenu.add(menuItem); fileMenu.addSeparator(); menuItem = new JMenuItem("Exit"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK)); menuItem.setMnemonic(KeyEvent.VK_X); menuItem.addActionListener(this); fileMenu.add(menuItem); /*------------------------ Document menu ---------------------------------*/ // Create the Document menu docMenu = new JMenu("Document"); docMenu.setMnemonic(KeyEvent.VK_D); // Add the Document Menu to the menu bar menuBar.add(docMenu); // Create a few items to add to the document menu menuItem = new JMenuItem("First Document"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.CTRL_MASK)); menuItem.setMnemonic(KeyEvent.VK_D); menuItem.addActionListener(this); docMenu.add(menuItem); menuItem = new JMenuItem("Last Document"); menuItem.addActionListener(this); menuItem.setEnabled(false); docMenu.add(menuItem); menuItem = new JMenuItem("Next Document"); menuItem.addActionListener(this); menuItem.setEnabled(false); docMenu.add(menuItem); menuItem = new JMenuItem("Open Document"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK)); menuItem.setMnemonic(KeyEvent.VK_O); menuItem.addActionListener(this); docMenu.add(menuItem); docMenu.addSeparator(); menuItem = new JMenuItem("Create Document"); menuItem.addActionListener(this); docMenu.add(menuItem); docMenu.addSeparator(); menuItem = new JMenuItem("Delete Document"); menuItem.addActionListener(this); menuItem.setEnabled(false); docMenu.add(menuItem); docMenu.addSeparator(); menuItem = new JMenuItem("Import Document(s)"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_I, ActionEvent.CTRL_MASK)); menuItem.setMnemonic(KeyEvent.VK_I); menuItem.addActionListener(this); docMenu.add(menuItem); docMenu.addSeparator(); menuItem = new JMenuItem("Close Document"); menuItem.addActionListener(this); docMenu.add(menuItem); /*---------------- Transaction Menu ----------------------*/ // Create the Transaction menu transMenu = new JMenu("Transaction"); transMenu.setMnemonic(KeyEvent.VK_T); // Add the transaction Menu to the menu bar menuBar.add(transMenu); // Create a few items to add to the transaction menu menuItem = new JMenuItem("Begin Transaction"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_B, ActionEvent.CTRL_MASK)); menuItem.setMnemonic(KeyEvent.VK_B); menuItem.addActionListener(this); transMenu.add(menuItem); menuItem = new JMenuItem("Commit Transaction"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK)); menuItem.setMnemonic(KeyEvent.VK_C); menuItem.addActionListener(this); transMenu.add(menuItem); menuItem = new JMenuItem("Abort Transaction"); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.CTRL_MASK)); menuItem.setMnemonic(KeyEvent.VK_A); menuItem.addActionListener(this); transMenu.add(menuItem); return menuBar; } /*========================================================================= * Desc: Method to choose and open a database. *========================================================================*/ private void openDatabase() { String sDatabaseName = null; String sDirectory = null; JFileChooser fileChooser = new JFileChooser(); XFileFilter dbFilter = new XFileFilter(".db"); fileChooser.setFileFilter(dbFilter); fileChooser.setCurrentDirectory(new File(m_sDirectory)); fileChooser.setDialogTitle("Open Database"); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); if (fileChooser.showDialog(null, "Open Database") == JFileChooser.APPROVE_OPTION) { try { sDatabaseName = new String(fileChooser.getSelectedFile().getPath()); sDirectory = new String(fileChooser.getCurrentDirectory().getPath()); if (m_jDb != null) { closeDatabase(); } // If this fails, we will throw an exception. m_jDb = m_dbSystem.dbOpen(sDatabaseName, null, null, null, true); m_status.setDatabasePath(sDatabaseName); m_status.setDatabaseOpen(true); m_sDatabaseName = sDatabaseName; m_sDirectory = sDirectory; } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } } /*========================================================================= * Desc: Method to close the current database. *========================================================================*/ private void closeDatabase() { if (m_jDb == null) { return; } // Make sure we clear out the document list. if (m_mainDisplay.getComponentCount() > 0) { closeAllDocuments(); } m_jDb.close(); m_jDb = null; m_status.setDatabaseOpen(false); m_status.setDatabasePath(null); m_status.setDocId(-1); m_status.setNodeId(-1); m_sDatabaseName = null; if (m_selected != null) { m_selected.deselectNode(); m_selected = null; } // m_iCurrentNode = NO_NODES; m_iLastNode = NO_NODES; m_status.m_iCurrentNode = NO_NODES; m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); updateDisplay(); } /*========================================================================= * Desc: Method to close the current database. *========================================================================*/ private void createDatabase() { String sDatabaseName = null; String sDirectory = null; JFileChooser fileChooser = new JFileChooser(); XFileFilter dbFilter = new XFileFilter(".db"); fileChooser.setFileFilter(dbFilter); fileChooser.setCurrentDirectory(new File(m_sDirectory)); fileChooser.setDialogTitle("Create Database"); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); if (fileChooser.showDialog(null, "Create Database") == JFileChooser.APPROVE_OPTION) { sDatabaseName = new String( fileChooser.getSelectedFile().getPath()); sDirectory = new String( fileChooser.getCurrentDirectory().getPath()); try { if (m_jDb != null) { closeDatabase(); } // If this fails, we will throw an exception. m_jDb = m_dbSystem.dbCreate( sDatabaseName, "", "", "", "", null); m_status.setDatabasePath(sDatabaseName); m_status.setDatabaseOpen(true); m_sDatabaseName = sDatabaseName; m_sDirectory = sDirectory; } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } } /*========================================================================= * Desc: Method to delete document node. *========================================================================*/ private void deleteNode( NodePanel np) { DOMNode jNode = null; boolean bTransBegun = false; Document doc = null; boolean bIsRoot = false; String sMessage; long lDocId; try { jNode = m_jDb.getNode(np.getCollection(), np.getNodeId(), null); lDocId = np.getDocId(); // Check to see if this is a root node. Ultimately we will call delete document // to handle it. if (np.getNodeId() == lDocId) { bIsRoot = true; doc = new Document("<" + jNode.getLocalName() + ">", np.getDocId(), np.getCollection()); } if (jNode.getNodeType() == FlmDomNodeType.DATA_NODE) { sMessage = new String("Delete data node"); } else if (bIsRoot) { sMessage = new String("Delete document: <" + jNode.getLocalName() + ">"); } else { sMessage = new String("Delete node: <" + jNode.getLocalName() + ">"); } if (JOptionPane.showConfirmDialog( this, sMessage) == JOptionPane.OK_OPTION) { boolean bHasNextSibling = false; // Check for a next sibling. if (jNode.hasNextSibling()) { try { DOMNode jNext = jNode.getNextSibling(null); bHasNextSibling = true; // This is here to silence the warning that jNext is never read. if (jNext != null) { jNext = null; } } catch (XFlaimException e) { // Ignore this. } } // Collapse the current row. if (np.isExpanded()) { collapseNode(np); } // Begin a transaction if (!m_status.getTransaction()) { m_jDb.transBegin(TransactionType.UPDATE_TRANS, 0, 0); bTransBegun = true; } // Delete the node. jNode.deleteNode(); // Commit if (bTransBegun) { m_jDb.transCommit(); bTransBegun = false; } // Remove the current node from the display removeRow(np.getRow()); // If the new row is a parent, then we need to collapse it so // the display looks ok. if (!bHasNextSibling) { if (np.isExpanded() && lDocId == np.getDocId()) { collapseNode(np); } } m_status.setDocId(np.getDocId()); m_status.setNodeId(np.getNodeId()); if (bIsRoot) { m_vDocList.remove(doc); } } } catch(XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } finally { if (bTransBegun) { try { m_jDb.transAbort(); } catch (XFlaimException ex) { // ignore this one. } } } } /*========================================================================= * Desc: Method to remove (delete) a database. *========================================================================*/ private void removeDatabase() { String sDatabaseName = m_sDatabaseName; // If there is already an open database close it. if (sDatabaseName != null) { closeDatabase(); } else { // We need to choose a database to remove. JFileChooser fileChooser = new JFileChooser(); XFileFilter dbFilter = new XFileFilter(".db"); fileChooser.setFileFilter(dbFilter); fileChooser.setCurrentDirectory(new File(m_sDirectory)); fileChooser.setDialogTitle("Remove Database"); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); if (fileChooser.showDialog(null, "Remove Database") == JFileChooser.APPROVE_OPTION) { sDatabaseName = new String( fileChooser.getSelectedFile().getPath()); if (m_jDb != null) { closeDatabase(); } } } if (sDatabaseName != null) { // If this fails, we will throw an exception. try { m_dbSystem.dbRemove( sDatabaseName, "", "", true); } catch (XFlaimException e) { JOptionPane.showConfirmDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } } /*========================================================================= * Desc: Method to choose and import a document or directory into the current database. *========================================================================*/ private void importDocument() { String sDirectory = null; JFileChooser fileChooser = new JFileChooser(); XFileFilter xmlFilter = new XFileFilter(".xml"); int iCollection; // Make sure we have a database open. if (!m_status.getDatabaseOpen()) { JOptionPane.showMessageDialog(this, "There is no open database. Import operation failed."); return; } fileChooser.setFileFilter(xmlFilter); fileChooser.setCurrentDirectory(new File(m_sDirectory)); fileChooser.setDialogTitle("Import XML File or Directory"); fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { sDirectory = new String( fileChooser.getCurrentDirectory().getPath()); iCollection = selectCollection(); if (iCollection == 0) { // Cancelled! return; } try { FileImporter fi = new FileImporter( this, m_dbSystem, m_sDatabaseName, iCollection, new String( fileChooser.getSelectedFile().getPath()), sDirectory, fileChooser.getSelectedFile().list()); fi.start(); // Save the last selected directory. m_sDirectory = sDirectory; } catch (XFlaimException e) { JOptionPane.showConfirmDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } } /*========================================================================= * Desc: Method to retrieve the first document from the database. *========================================================================*/ private void getFirstDocument() { DOMNode jDoc = null; int iCollection; if (m_status.getDatabaseOpen()) { // Need to get the collection. iCollection = selectCollection(); if (iCollection > 0) { try { jDoc = m_jDb.getFirstDocument(iCollection, null); m_vDocList.add(new Document("<" + jDoc.getLocalName() + ">", jDoc.getNodeId(), iCollection)); if (m_iLastNode < LAST_NODE) { NodePanel np = (NodePanel)m_vNodeList.get(++m_iLastNode); np.buildLabel( jDoc, false, false, m_bDocList); expandNode(np, true); m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); if (m_selected == null) { selectNode(np); } } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } } else { // Put up a dialog to indicate that there is no database open yet. JOptionPane.showMessageDialog( this, "Cannot retrieve a document - no open database.", "Incomplete Operation", JOptionPane.INFORMATION_MESSAGE); } } /*========================================================================= * Desc: Method to present a list of documents to open. *========================================================================*/ private void openDocument() { if (m_status.getDatabaseOpen()) { // Need to get the collection. int iCollection = selectCollection(); if (iCollection > 0) { selectDocument(iCollection); } } else { // Put up a dialog to indicate that there is no database open yet. JOptionPane.showMessageDialog( this, "Cannot retrieve a document - no open database.", "Incomplete Operation", JOptionPane.INFORMATION_MESSAGE); } } /*========================================================================= * Desc: Method to a document of choice from the database. *========================================================================*/ private void openDocument( int iCollection, long lDocId) { DOMNode jDoc = null; try { if (lDocId > 0) { jDoc = m_jDb.getNode(iCollection, lDocId, null); m_vDocList.add(new Document("<" + jDoc.getLocalName() + ">", jDoc.getNodeId(), iCollection)); if (m_iLastNode < LAST_NODE) { NodePanel np = (NodePanel)m_vNodeList.get(++m_iLastNode); np.buildLabel(jDoc, false, false, m_bDocList); expandNode(np, true); m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); if (m_selected == null) { selectNode(np); } } } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred:" + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } /*========================================================================= * Desc: Method to close the document of choice. *========================================================================*/ private void closeDocument() { int iItem; boolean bDocFound = false; if (m_vDocList.size() > 1) { // Need to select the document to close. iItem = selectDocumentFromList(); if (iItem >= 0) { Document doc = (Document)m_vDocList.get(iItem); // Find the root document node and remove it. for (int i = 0; i <= m_iLastNode; i++) { NodePanel np = (NodePanel)m_vNodeList.get(i); if (np.getDocId() == doc.m_lDocId) { closeDocument(np); bDocFound = true; break; } } // The document may not have been visible on the screen, so we must remove it // from the document list. if (!bDocFound) { m_vDocList.removeElementAt(iItem); } } } else { if (m_vDocList.size() == 1) { closeAllDocuments(); } } updateDisplay(); } /*========================================================================= * Desc: Method to close the document owned by the node panel passed in. *========================================================================*/ private void closeDocument( NodePanel np) { int iRow = np.getRow(); int iItem; try { DOMNode jNode = m_jDb.getNode( np.getCollection(), np.getNodeId(), null); Document doc = new Document("<" + jNode.getLocalName() + ">", np.getDocId(), np.getCollection()); iItem = m_vDocList.indexOf(doc); if (iItem >= 0) { // Now let's clean up the display. // First, if the document is expanded, we need to collapse it. if (np.isExpanded()) { collapseNode(np); } m_vDocList.removeElementAt(iItem); removeRow(iRow); if (m_vDocList.size() == 0) { m_status.setDocId(0); m_status.setNodeId(0); } if (m_selected != null) { selectNode(m_selected); } } else { JOptionPane.showMessageDialog( this, "Failed to close current document: Document not found", "Document Not Closed", JOptionPane.WARNING_MESSAGE); } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } /*========================================================================= * Desc: Method to close all documents *========================================================================*/ private void closeAllDocuments() { for (int i= FIRST_NODE; i <= LAST_NODE; i++) { NodePanel np = (NodePanel)m_vNodeList.get(i); np.reset(); } m_vDocList.removeAllElements(); // m_iCurrentNode = NO_NODES; m_iLastNode = NO_NODES; m_selected = null; m_status.m_iCurrentNode = NO_NODES; m_status.m_iLastNode = m_iLastNode; m_status.setDocId(0); m_status.setNodeId(0); } /*========================================================================= * Desc: Method to select the collection *========================================================================*/ private int selectCollection() { Collection coll = new Collection("invalid", 0); CollectionSelector CS = new CollectionSelector(this, m_dbSystem, m_jDb, coll); CS.dispose(); return coll.m_iNumber; } /*========================================================================= * Desc: Method to select document *========================================================================*/ private void selectDocument( int iCollection ) { Document doc = null; Thread t = null; doc = new Document("invalid", 0, 0); XEdit DS = new XEdit(this, "Document Selector", m_jDb, iCollection, doc); GraphicsConfiguration gc = getGraphicsConfiguration(); Rectangle bounds = gc.getBounds(); int iHeight = getHeight(); int iWidth = getWidth(); DS.setLocation(Math.max(0, (bounds.width - iWidth)/2), Math.max(0, (bounds.height - iHeight)/2)); t = new Thread((Runnable)DS); t.start(); } /*========================================================================= * Desc: Method to select document from the list of open documents. *========================================================================*/ private int selectDocumentFromList() { OpenDocumentSelector ods = new OpenDocumentSelector( this, m_vDocList); return ods.showDialog(); } // Default protection means the package can see this method. void updateDisplay() { setContentPane(m_mainPanel); } // Service method to compare a JPanel object to the main panel boolean isMainPanel( JPanel panel) { if (panel == m_mainDisplay) { return true; } else { return false; } } /* (non-Javadoc) * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) */ public void mouseClicked(MouseEvent e) { NodePanel np = null; np = (NodePanel)e.getSource(); selectNode(np); if (e.getClickCount() == 1 && !m_bDocList) { if (e.getButton() == MouseEvent.BUTTON1) { if (np.isExpanded()) { collapseNode(np); } else { expandNode(np, false); } } else if (e.getButton() == MouseEvent.BUTTON3) { JMenuItem menuItem = null; DOMNode jNode = null; if (m_status.getDatabaseOpen()) { try { jNode = m_jDb.getNode( np.getCollection(), np.getNodeId(), jNode); // popup the document menu. m_popup = new JPopupMenu("Document Node Options"); if (np.getDocId() != NO_NODES) { if (np.getDocId() == np.getNodeId()) { menuItem = m_popup.add("Close Document"); menuItem.addActionListener(this); m_popup.addSeparator(); } if (np.hasChildren()) { if (np.isExpanded()) { menuItem = m_popup.add("Collapse Node"); } else { menuItem = m_popup.add("Expand Node"); } menuItem.addActionListener(this); m_popup.addSeparator(); } // Make a sub-menu for the delete JMenu delMenu = new JMenu("Delete"); menuItem = delMenu.add("Delete Node"); menuItem.addActionListener(this); menuItem = delMenu.add("Delete Attribute"); menuItem.addActionListener(this); if (!jNode.hasAttributes()) { menuItem.setEnabled(false); } menuItem = delMenu.add("Delete Annotation"); menuItem.addActionListener(this); if (!jNode.hasAnnotation()) { menuItem.setEnabled(false); } m_popup.add(delMenu); menuItem = m_popup.add("Add Node"); menuItem.addActionListener(this); // Need to make the edit sub-menu. JMenu editMenu = new JMenu("Edit Node"); menuItem = editMenu.add("Edit Value"); // Test for a value try { String sValue = jNode.getString(); if (sValue.length() == 0) { menuItem.setEnabled(false); } } catch (XFlaimException ee) { menuItem.setEnabled(false); } menuItem.addActionListener(this); menuItem = editMenu.add("Edit Attribute"); if (!jNode.hasAttributes()) { menuItem.setEnabled(false); } menuItem.addActionListener(this); menuItem = editMenu.add("Edit Annotation"); if (!jNode.hasAnnotation()) { menuItem.setEnabled(false); } menuItem.addActionListener(this); m_popup.add(editMenu); } else { menuItem = m_popup.add("Add Document"); menuItem.addActionListener(this); menuItem.setEnabled(false); } } catch (XFlaimException ex) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + ex.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } // Need to make sure the menu appears close to where our window is located. Point p = e.getPoint(); Point p1 = np.getLocation(); m_popup.show(this, p1.x + p.x, p1.y + p.y); } } } if (e.getClickCount() == 2) { if (e.getButton() == MouseEvent.BUTTON1) { // Are we selecting a document? if (m_bDocList) { m_doc.m_iCollection = np.getCollection(); m_doc.m_lDocId = np.getDocId(); try { DOMNode jDoc = m_jDb.getNode(m_doc.m_iCollection, m_doc.m_lDocId, null); m_doc.m_sName = "<" + jDoc.getLocalName() + ">"; if (m_parent != null) { // Open the document in the parent m_parent.openDocument(m_doc.m_iCollection, m_doc.m_lDocId); this.dispose(); } } catch (XFlaimException ex) { JOptionPane.showMessageDialog( this, "Database Exception ocurred: " + ex.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } } } } /* (non-Javadoc) * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) */ public void mouseEntered(MouseEvent e) { // Do nothing. } /* (non-Javadoc) * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) */ public void mouseExited(MouseEvent e) { // Do Nothing } /* (non-Javadoc) * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) */ public void mousePressed(MouseEvent e) { // Do Nothing } /* (non-Javadoc) * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) */ public void mouseReleased(MouseEvent e) { // Do Nothing } /* (non-Javadoc) * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) */ public void keyPressed(KeyEvent e) { // Do Nothing } /* (non-Javadoc) * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) */ public void keyReleased(KeyEvent e) { int key = e.getKeyCode(); if (m_vDocList.isEmpty() && !m_bDocList) { return; } switch (key) { case KeyEvent.VK_KP_UP: case KeyEvent.VK_UP: { moveUp(); break; } case KeyEvent.VK_KP_DOWN: case KeyEvent.VK_DOWN: { moveDown(); break; } case KeyEvent.VK_PAGE_UP: { pageUp(); break; } case KeyEvent.VK_PAGE_DOWN: { pageDown(); break; } case KeyEvent.VK_KP_RIGHT: case KeyEvent.VK_RIGHT: { // Expand. if (!m_selected.isExpanded()) { expandNode(m_selected, false); } break; } case KeyEvent.VK_KP_LEFT: case KeyEvent.VK_LEFT: { // Collapse if (m_selected.isExpanded()) { collapseNode(m_selected); } break; } case KeyEvent.VK_ENTER: { // Are we selecting a document? if (m_bDocList) { m_doc.m_iCollection = m_selected.getCollection(); m_doc.m_lDocId = m_selected.getDocId(); try { DOMNode jDoc = m_jDb.getNode(m_doc.m_iCollection, m_doc.m_lDocId, null); m_doc.m_sName = "<" + jDoc.getLocalName() + ">"; if (m_parent != null) { // Open the document in the parent m_parent.openDocument(m_doc.m_iCollection, m_doc.m_lDocId); this.dispose(); } } catch (XFlaimException ex) { JOptionPane.showMessageDialog( this, "Database Exception ocurred: " + ex.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } } } } /** * */ private void moveUp() { if (m_selected == null) { // First row not set yet. return; } if (m_selected.getRow() > 0) { selectNode((NodePanel)m_vNodeList.get(m_selected.getRow() - 1)); } else { // We are going to have to move eveyone down one row first. // Then get the previous row. if (scrollUp()) { selectNode((NodePanel)m_vNodeList.get(m_selected.getRow() - 1)); } } } /** * */ private boolean scrollUp() { NodePanel npTo; NodePanel npFrom; if (m_selected == null) { return false; } if (hasPreviousNode()) { for (int i = LAST_NODE; i > 0; --i) { npTo = (NodePanel)m_vNodeList.get(i); npFrom = (NodePanel)m_vNodeList.get(i - 1); npTo.copyNode(npFrom); } // Move the selected Node down one row too. selectNode((NodePanel)m_vNodeList.get(m_selected.getRow() + 1)); // Now we need to get the previous row. Due to the way this is // architected, we should be looking at the currently selected row // to determine the previous row. The currently selected row is supposed to // be the second row now. If there isn't a previous row, we will get a false // return value. if (!m_bDocList) { return(getPrevNode()); } else { return(getPrevDocument()); } } else { return false; } } /** * @return */ private boolean hasPreviousNode() { NodePanel np = m_selected; // Should be the first row, i.e. row 0. DOMNode jNode = null; Document doc = null; try { jNode = m_jDb.getNode(np.getCollection(), np.getDocId(), null); if (!m_bDocList) { // With a standard XEdit, we check to see if we have another open // document. doc = new Document("<" + jNode.getLocalName() + ">", np.getDocId(), np.getCollection()); // If we're looking at the root node, then we need to find out if there // is another document to view previous to this one. if (np.getDocId() == np.getNodeId() && !np.isClosing()) { if (m_vDocList.indexOf(doc) > 0) { return true; } else { return false; } } else { return true; } } else { // With a DocList, we check to see if there is a previous document. try { jNode = jNode.getPreviousDocument(jNode); return true; } catch (XFlaimException ex) { if (ex.getRCode() == RCODE.NE_XFLM_DOM_NODE_NOT_FOUND) { return false; } else { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + ex.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); return false; } } } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); return false; } } /** * Fetch the previous node relative to the selected row. Typically, the * currently selected row is row 0 when this method is invoked. * * @return boolean, signals whether the previous node was found or not. */ private boolean getPrevNode() { NodePanel np = m_selected; int iSelectedRow = np.getRow(); DOMNode jNode = null; Document doc = null; try { jNode = m_jDb.getNode(np.getCollection(), np.getNodeId(), null); if (np.isClosing()) { // See if we can get a child node if (jNode.hasChildren()) { jNode = jNode.getLastChild(jNode); np = (NodePanel)m_vNodeList.get(iSelectedRow - 1); np.reset(); np.buildLabel(jNode, true, false, m_bDocList); return true; } } // Check for a previous sibling. try { jNode = jNode.getPreviousSibling(jNode); np = (NodePanel)m_vNodeList.get(iSelectedRow - 1); np.reset(); np.buildLabel(jNode, true, jNode.hasChildren() ? true : false, m_bDocList); return true; } catch (XFlaimException e) { // Do nothing, we just want to make sure we catch it. } // Check for a parent. if (np.getNodeId() != np.getDocId()) { jNode = jNode.getParentNode(jNode); np = (NodePanel)m_vNodeList.get(iSelectedRow - 1); np.reset(); np.buildLabel(jNode, true, false, m_bDocList); return true; } // Is there a previous document to get? doc = new Document("<" + jNode.getLocalName() + ">", np.getDocId(), np.getCollection()); int iIndex = m_vDocList.indexOf(doc); if (iIndex > 0) { doc = (Document)m_vDocList.get(iIndex - 1); jNode = m_jDb.getNode(doc.m_iCollection, doc.m_lDocId, jNode); np = (NodePanel)m_vNodeList.get(iSelectedRow - 1); np.reset(); np.buildLabel(jNode, true, true, m_bDocList); return true; } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); return false; } return false; } /** * */ private void pageDown() { // Move down one full page worth. The moveDown // method will stop if we run out of nodes to scroll to. for (int i = 0; i < LAST_NODE; i++) { moveDown(); } } /** * */ private void pageUp() { // Move up one full page worth. The moveUp method // will stop if we reach the top. for (int i = 0; i < LAST_NODE; i++) { moveUp(); } } /** * */ private void moveDown() { if (m_selected == null) { return; } if (m_selected.getRow() < m_iLastNode) { selectNode((NodePanel)m_vNodeList.get(m_selected.getRow()+ 1)); } else { // We are going to have to move eveyone up one row first. // Then get the next row. if (scrollDown()) { selectNode((NodePanel)m_vNodeList.get(m_selected.getRow() + 1)); } } } /** * Scroll the screen down one row. This will pick up the * next row from off the screen if there is one. * @return */ private boolean scrollDown() { NodePanel npTo; NodePanel npFrom; if (m_selected == null) { return false; } else { if (hasNextNode()) { for (int i = 0; i < LAST_NODE; i++) { npTo = (NodePanel)m_vNodeList.get(i); npFrom = (NodePanel)m_vNodeList.get(i + 1); npTo.copyNode(npFrom); } // Backup one row and select it. selectNode((NodePanel)m_vNodeList.get(m_selected.getRow() - 1)); // Now we need to get the next row. Due to the way this is // architected, we should be looking at the currently selected row // to determine the next row. The currently selected row is supposed to // be the next to last row now. If there isn't a next row, we will get a false // return value. if (!m_bDocList) { return(getNextNode(true)); } else { return(getNextDocument()); } } else { return false; } } } /** * @return */ private boolean hasNextNode() { NodePanel np = m_selected; DOMNode jNode = null; Document doc = null; try { jNode = m_jDb.getNode(np.getCollection(), np.getDocId(), null); if (!m_bDocList) { // Standard XEdit - build a Document object to compare with. doc = new Document("<" + jNode.getLocalName() + ">", np.getDocId(), np.getCollection()); // If we're looking at the root node, then we need to find out if there // is another document to view after this one. if (np.getDocId() == np.getNodeId() && (np.isClosing() || !np.isExpanded())) { int i = m_vDocList.indexOf(doc); if (i >= 0 && i < m_vDocList.size() - 1) { return true; } else { return false; } } else { return true; } } else { // This XEdit is a document list, so just see if we can get a next document. try { jNode = jNode.getNextDocument(jNode); return true; } catch (XFlaimException ex) { if (ex.getRCode() == RCODE.NE_XFLM_DOM_NODE_NOT_FOUND) { return false; } else { JOptionPane.showMessageDialog( this, "Database Exception Occurred" + ex.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); return false; } } } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); return false; } } /** * Fetch the next node, relative to the currently selected node. This may * be the first child node, or the next sibling node, the parent node or the * root node of the next document. If bStartAtChild is false, it will * skip looking for the first child node. * * @param bStartAtChild boolean parameter to signal whether to look for the * first child or not. * * @return boolean - next node found or not found. */ private boolean getNextNode( boolean bStartAtChild) { NodePanel np = m_selected; int iSelectedRow = np.getRow(); DOMNode jNode = null; Document doc = null; try { jNode = m_jDb.getNode(np.getCollection(), np.getNodeId(), jNode); if (bStartAtChild && !np.isClosing() && np.isExpanded()) { // See if we can get a child node if (jNode.hasChildren()) { jNode = jNode.getFirstChild(jNode); np = (NodePanel)m_vNodeList.get(iSelectedRow + 1); np.reset(); np.buildLabel(jNode, true, false, m_bDocList); return true; } } // Check for a next sibling. try { jNode = jNode.getNextSibling(jNode); np = (NodePanel)m_vNodeList.get(iSelectedRow + 1); np.reset(); np.buildLabel(jNode, true, false, m_bDocList); return true; } catch (XFlaimException e) { // Do nothing, we just want to make sure we catch it. } // Check for a parent. if (np.getNodeId() != np.getDocId()) { jNode = jNode.getParentNode(jNode); np = (NodePanel)m_vNodeList.get(iSelectedRow + 1); np.reset(); np.buildLabel(jNode, true, true, m_bDocList); return true; } // Is there a next document to get? doc = new Document("<" + jNode.getLocalName() + ">", np.getDocId(), np.getCollection()); int iIndex = m_vDocList.indexOf(doc); if (iIndex < m_vDocList.size() - 1) { doc = (Document)m_vDocList.get(iIndex + 1); jNode = m_jDb.getNode(doc.m_iCollection, doc.m_lDocId, jNode); np = (NodePanel)m_vNodeList.get(iSelectedRow + 1); np.reset(); np.buildLabel(jNode, true, false, m_bDocList); return true; } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); return false; } return false; } /* (non-Javadoc) * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent) */ public void keyTyped(KeyEvent e) { // Do nothing } /*------------------------------------------------------------------------- * Desc: Method to highlight a row given the NodePanel. *-----------------------------------------------------------------------*/ private void selectNode( NodePanel np) { long lDocId; long lNodeId; // Don't select anything if the NodePanel does not have a document // that is displaying. if (np.getDocId() == NO_NODES) { return; } if (m_selected != null) { m_selected.deselectNode(); } m_selected = np; m_selected.selectNode(); m_status.m_iCurrentNode = m_selected.getRow(); lDocId = np.getDocId(); m_status.setDocId(lDocId); lNodeId = np.getNodeId(); m_status.setNodeId(lNodeId); } /*------------------------------------------------------------------------- * Desc: Method to expand a node one level given the NodePanel. *-----------------------------------------------------------------------*/ private void expandNode( NodePanel np, boolean bDeep) { DOMNode refNode; DOMNode childNode = null; boolean bFirst = true; m_iExpandedRow = np.getRow(); if (!np.hasChildren()) { return; } if (np.isClosing()) { return; } try { refNode = m_jDb.getNode(np.getCollection(), np.getNodeId(), null); np.buildLabel(refNode, true, false, m_bDocList); for (;m_iExpandedRow < LAST_NODE;) { if (bFirst) { bFirst = false; childNode = refNode.getFirstChild(null); } else { try { childNode = childNode.getNextSibling(childNode); } catch (XFlaimException e) { if (e.getRCode() == RCODE.NE_XFLM_DOM_NODE_NOT_FOUND) { break; } else { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } } insertRow(++m_iExpandedRow, childNode, bDeep, false); if (bDeep) { expandNode((NodePanel)m_vNodeList.get(m_iExpandedRow), bDeep); } } // See if we have room to put in a closing row. if (m_iExpandedRow + 1 <= LAST_NODE) { insertRow(++m_iExpandedRow, refNode, true, true); } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } /*------------------------------------------------------------------------- * Desc: Method to collapse a node given the NodePanel. This could result * in multiple levels being collapsed. *-----------------------------------------------------------------------*/ private void collapseNode( NodePanel np) { int iOpeningRow; int iClosingRow = -1; long lNodeId; NodePanel npOpening = np; NodePanel npClosing = null; int iCollection; boolean bHasClosing = false; if (!np.isExpanded() || !np.hasChildren()) { return; } lNodeId = np.getNodeId(); iCollection = np.getCollection(); try { DOMNode refNode = m_jDb.getNode(iCollection, lNodeId, null); if (np.isClosing()) { bHasClosing = true; npClosing = np; iClosingRow = np.getRow(); // Locate the opening instance of this node, if it is present on // the screen. If it can't be found on the screen, this node will // become the opening node and will be displayed as the first row // on the screen. iOpeningRow = iClosingRow - 1; while (iOpeningRow >= 0) { npOpening = (NodePanel)m_vNodeList.get(iOpeningRow); if (npOpening.getNodeId() == lNodeId) { break; } --iOpeningRow; } } else { npOpening = np; iOpeningRow = np.getRow(); } // Can we short circuit the process by checking for the root node? //if (lNodeId == np.getDocId()) //{ // collapseDocument(npOpening); // return; //} // Find the closing node. if (!bHasClosing) { for (iClosingRow = iOpeningRow + 1; iClosingRow <= m_iLastNode; iClosingRow++) { npClosing = (NodePanel)m_vNodeList.get(iClosingRow); if (npClosing.getNodeId() == lNodeId) { bHasClosing = true; break; } } } if (!bHasClosing) { clearNodes(npOpening.getRow() + 1, m_iLastNode); // When we build this node, we must first set the closing as true // so we can check for another node. We will rebuild it again // when we finish. npOpening.buildLabel(refNode, false, false, m_bDocList); selectNode(npOpening); m_iLastNode = npOpening.getRow(); m_status.m_iCurrentNode = m_iLastNode; m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); // If we have just collapsed the last row, there is no need to get another row. if (m_iLastNode < LAST_NODE) { if (getNextNode(false)) { m_iLastNode++; m_status.m_iLastNode = m_iLastNode; // Need to expand the new document that just got exposed. selectNode((NodePanel)m_vNodeList.get(m_selected.getRow() + 1)); // Will get reset on the way out. m_status.m_iCurrentNode = m_selected.getRow(); m_status.updateLabel(); np = m_selected; // Cannot expand the closing node of a document. if (np.isClosing()) { if (m_iLastNode < LAST_NODE && getNextNode(false)) { m_iLastNode++; selectNode((NodePanel)m_vNodeList.get(m_selected.getRow() + 1)); m_status.m_iCurrentNode = m_selected.getRow(); m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); expandNode(m_selected, true); } } else { expandNode(m_selected, true); } selectNode(npOpening); } } } else // Have a closing node { // If we have an opening node, then we need to redraw it first, // before we collapse the rest. if (iOpeningRow >= 0) { npOpening.buildLabel(refNode, false, false, m_bDocList); } // We need to remove rows one at a time until we get to the closing row. for (int i = iOpeningRow + 1; (iOpeningRow >= 0) ? i <= iClosingRow : i < iClosingRow; i++) { removeRow(iOpeningRow+1); } // If we did not have an opening row, we need to build the row now. if (iOpeningRow < 0) { npOpening.buildLabel(refNode, false, false, m_bDocList); } selectNode(npOpening); if (m_iLastNode < npOpening.getRow()) { m_iLastNode = npOpening.getRow(); m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); } } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } /*------------------------------------------------------------------------- * Desc: Method to collapse a document given the root NodePanel. *-----------------------------------------------------------------------*/ /* private void collapseDocument( NodePanel npDoc) { DOMNode docNode; try { docNode = m_jDb.getNode(npDoc.getCollection(), npDoc.getDocId(), null); clearNodes(npDoc.getRow() + 1, m_iLastNode); // When we build this node, we must first set the closing as true // so we can check for another document. We will rebuid it again // when we finish. npDoc.buildLabel(docNode, false, true); selectNode(npDoc); m_iLastNode = m_iCurrentNode; if (getNextNode(false)) { // Need to expand the new document that just got exposed. m_iCurrentNode++; // Will get reset on the way out. expandNode((NodePanel)m_vNodeList.get(m_iCurrentNode), true); selectNode(npDoc); // Resets m_iCurrentNode. } npDoc.buildLabel(docNode, false, false); } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } */ /*------------------------------------------------------------------------- * Desc: Method to clear the nodes on display within the range specified. *-----------------------------------------------------------------------*/ private void clearNodes( int iFromNode, int iToNode) { if (iFromNode > iToNode) { return; } for (int i = iFromNode; i <= iToNode; i++) { NodePanel np = (NodePanel)m_vNodeList.get(i); np.reset(); } } /*------------------------------------------------------------------------- * Desc: Method to move a row down one and insert a new row in its place. *-----------------------------------------------------------------------*/ private void insertRow( int iRow, DOMNode refNode, boolean bExpanded, boolean bClosing) { NodePanel npCopy = null; NodePanel npInsert = null; // Move them down one row to make room. for (int i = LAST_NODE; i > iRow; i--) { npInsert = (NodePanel)m_vNodeList.get(i); npCopy = (NodePanel)m_vNodeList.get(i-1); npInsert.copyNode(npCopy); } // Copy the node that is at the current location into a temporary // NodePanel. npInsert = (NodePanel)m_vNodeList.get(iRow); npCopy = new NodePanel(this, 0); // The row is not copied across NodePanels. npCopy.copyNode(npInsert); try { npInsert.buildLabel(refNode, bExpanded, bClosing, m_bDocList); // We cannot hold more than LAST_NODE nodes, so we only increment // the count till we get there. if (m_iLastNode < LAST_NODE) { m_iLastNode++; m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); } } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } } /*------------------------------------------------------------------------- * Desc: Method to remove a row and move all other rows up one position. * It will also add a new row to the bottom display if it can. *-----------------------------------------------------------------------*/ private void removeRow( int iRow ) { NodePanel npCopy = null; NodePanel npInsert = null; NodePanel np; NodePanel npSelected = m_selected; // Move everybody up one row. for (int i = iRow; i < LAST_NODE; i++) { npInsert = (NodePanel)m_vNodeList.get(i); npCopy = (NodePanel)m_vNodeList.get(i+1); npInsert.copyNode(npCopy); } // We have one less node being displayed now. m_iLastNode--; m_status.m_iLastNode = m_iLastNode; // Clear the last line incase there is nothing left to display. np = (NodePanel)m_vNodeList.get(m_iLastNode + 1); np.reset(); // Since we have one more row, see if we can expand it. // Make sure we are looking at a valid row. if (m_iLastNode >= 0) { selectNode((NodePanel)m_vNodeList.get(m_iLastNode)); } else { m_selected = null; } m_status.m_iCurrentNode = m_iLastNode; m_status.updateLabel(); if (m_selected != null) { if (getNextNode(true)) { m_iLastNode++; m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); } } // If we just removed the first display row and there are no more rows // to display, then we should clear the currently selected row (node). if (m_selected != null) { selectNode(npSelected); m_status.m_iCurrentNode = npSelected.getRow(); m_status.updateLabel(); } } /*------------------------------------------------------------------------- * Desc: Method to show the initial document listing. *-----------------------------------------------------------------------*/ private boolean showDocumentList() { boolean bFirst = true; DOMNode jDoc = null; NodePanel np; int iRow = 0; // We will clear the screen first. clearNodes(0, LAST_NODE); try { for (iRow = 0; iRow <= LAST_NODE; iRow++) { m_status.m_iCurrentNode = iRow; m_status.updateLabel(); if (bFirst) { bFirst = false; jDoc = m_jDb.getFirstDocument(m_iCollection, jDoc); } else { jDoc = jDoc.getNextDocument(jDoc); } np = (NodePanel)m_vNodeList.get(iRow); np.buildLabel(jDoc, false, false, m_bDocList); } m_iLastNode = LAST_NODE; m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); } catch (XFlaimException e) { if (e.getRCode() != RCODE.NE_XFLM_DOM_NODE_NOT_FOUND) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } else { if (iRow == 0) { return false; } else { m_iLastNode = iRow - 1; m_status.m_iLastNode = m_iLastNode; m_status.updateLabel(); } } } selectNode((NodePanel)m_vNodeList.get(0)); m_status.m_iCurrentNode = 0; m_status.updateLabel(); return true; } private boolean getNextDocument() { DOMNode jDoc = null; NodePanel np = m_selected; int iSelectedRow = np.getRow(); try { jDoc = m_jDb.getNode(m_iCollection, np.getDocId(), jDoc); jDoc = jDoc.getNextDocument(jDoc); insertRow(iSelectedRow + 1, jDoc, false, false); return true; } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } return false; } private boolean getPrevDocument() { DOMNode jDoc = null; NodePanel np = m_selected; int iSelectedRow = np.getRow(); try { jDoc = m_jDb.getNode(m_iCollection, np.getDocId(), jDoc); jDoc = jDoc.getPreviousDocument(jDoc); insertRow(iSelectedRow - 1, jDoc, false, false); return true; } catch (XFlaimException e) { JOptionPane.showMessageDialog( this, "Database Exception occurred: " + e.getMessage(), "Database Exception", JOptionPane.ERROR_MESSAGE); } return false; } /* (non-Javadoc) * @see java.lang.Runnable#run() */ public void run() { if (m_bMustExit) { this.dispose(); } else { setVisible(true); } } /** * Method to add a new document node to the current database. This method * assumes that an UPDATE transaction has already been started. If one * has not been started, an exception will be thrown. * @param iCollection * @param iTag * @param sNodeValue * @return lDocId The new document root node id. * @throws XFlaimException */ public long addDocument( int iCollection, int iTag, String sNodeValue) throws XFlaimException { DOMNode jNode = null; long lNodeId = 0; if (m_status.getTransaction()) { jNode = m_jDb.createRootElement(iCollection, iTag); lNodeId = jNode.getNodeId(); if (sNodeValue != null && sNodeValue.length() > 0) { // Add an annotation note to the document. jNode.createAnnotation(jNode); jNode.setString(sNodeValue); } } else { JOptionPane.showMessageDialog( this, "Illegal State: Action requires Update Transaction", "Illegal State", JOptionPane.ERROR_MESSAGE); } return lNodeId; } /** * Method to add a new node to an existing document, relative to the * lNodeId parameter. * @param iCollection * @param iNodeType * @param iNodeTag * @param sNodeValue * @param bIsSiblingNode * @param lNodeId * @return * @throws XFlaimException */ public long addNode( int iCollection, int iNodeType, int iNodeTag, String sNodeValue, boolean bIsSiblingNode, long lNodeId) throws XFlaimException { long lAnchorNode = lNodeId; boolean bIsAttribute = false; if (m_status.getTransaction()) { DOMNode jNode = m_jDb.getNode( iCollection, lNodeId, null); if (iNodeType == FlmDomNodeType.ATTRIBUTE_NODE) { jNode = jNode.createAttribute( iNodeTag, jNode); bIsAttribute = true; } else { if (bIsSiblingNode) { // Create the sibling node jNode = jNode.createNode( iNodeType, iNodeTag, FlmInsertLoc.FLM_NEXT_SIB, jNode); } else { jNode = jNode.createNode( iNodeType, iNodeTag, FlmInsertLoc.FLM_LAST_CHILD, jNode); } } // Set the value. if (sNodeValue != null && sNodeValue.length() > 0) { jNode.setString(sNodeValue); } if (m_selected != null && lAnchorNode == m_selected.getNodeId()) { // See if we can refresh the selected node/row NodePanel np = m_selected; DOMNode jRefNode = m_jDb.getNode( np.getCollection(), lAnchorNode, null); if (np.isExpanded() && np.isClosing()) { collapseNode(np); // The original selected node may have changed. We now want to // expand the currently selected node. expandNode(m_selected, true); } else { np.buildLabel(jRefNode, np.isExpanded(), np.isClosing(), false); } } if (bIsAttribute) { return lAnchorNode; } else { return jNode.getNodeId(); } } else { JOptionPane.showMessageDialog( this, "Illegal State: Action requires Update Transaction", "Illegal State", JOptionPane.ERROR_MESSAGE); } return 0; } /** * The main program. * @param args */ public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { System.err.println( "Couldn't use the system look and feel: " + e.getMessage()); e.printStackTrace(); } JFrame ed = new XEdit("XFlaim Editor"); GraphicsConfiguration gc = ed.getGraphicsConfiguration(); Rectangle bounds = gc.getBounds(); int iHeight = ed.getHeight(); int iWidth = ed.getWidth(); ed.setLocation(Math.max(0, (bounds.width - iWidth)/2), Math.max(0, (bounds.height - iHeight)/2)); Thread t = new Thread((Runnable)ed); t.start(); } /** * Method to add an annotation node to an existing node. * @param iCollection * @param sAnnotation * @param lNodeId * @return */ public long addAnnotation( int iCollection, String sAnnotation, long lNodeId) throws XFlaimException { if (m_status.getTransaction()) { DOMNode jNode = m_jDb.getNode( iCollection, lNodeId, null); jNode = jNode.createAnnotation( jNode); // Set the value. if (sAnnotation != null && sAnnotation.length() > 0) { jNode.setString(sAnnotation); } if (m_selected != null && lNodeId == m_selected.getNodeId()) { // See if we can refresh the selected node/row NodePanel np = m_selected; DOMNode jRefNode = m_jDb.getNode( np.getCollection(), lNodeId, null); if (np.isExpanded() && np.isClosing()) { collapseNode(np); // The original selected node may have changed. We now want to // expand the currently selected node. expandNode(m_selected, true); } else { np.buildLabel(jRefNode, np.isExpanded(), np.isClosing(), false); } } return lNodeId; } else { JOptionPane.showMessageDialog( this, "Illegal State: Action requires Update Transaction", "Illegal State", JOptionPane.ERROR_MESSAGE); } return 0; } }