com.cladonia.xml.editor.Editor.java Source code

Java tutorial

Introduction

Here is the source code for com.cladonia.xml.editor.Editor.java

Source

/*
 * $Id: Editor.java,v 1.73 2005/08/09 14:32:31 tcurley Exp $
 *
 * Copyright (C) 2003 - 2004, Cladonia Ltd. All rights reserved.
 *
 * This software is the proprietary information of Cladonia Ltd.  
 * Use is subject to license terms.
 */

package com.cladonia.xml.editor;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JPopupMenu;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.CompoundBorder;
import javax.swing.border.MatteBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultCaret;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import org.bounce.event.DoubleClickListener;
import org.bounce.event.PopupListener;
import org.dom4j.Namespace;
import org.dom4j.Node;
import org.xml.sax.SAXParseException;
import com.cladonia.schema.AttributeInformation;
import com.cladonia.schema.AttributeValue;
import com.cladonia.schema.ElementInformation;
import com.cladonia.schema.SchemaDocument;
import com.cladonia.xml.CommonEntities;
import com.cladonia.xml.ExchangerDocument;
import com.cladonia.xml.ExchangerDocumentEvent;
import com.cladonia.xml.ExchangerDocumentListener;
import com.cladonia.xml.XAttribute;
import com.cladonia.xml.XElement;
import com.cladonia.xml.XMLError;
import com.cladonia.xngreditor.ErrorList;
import com.cladonia.xngreditor.ExchangerEditor;
import com.cladonia.xngreditor.ExchangerView;
import com.cladonia.xngreditor.StringUtilities;
import com.cladonia.xngreditor.URLUtilities;
import com.cladonia.xngreditor.ViewPanel;
import com.cladonia.xngreditor.XngrImageLoader;
import com.cladonia.xngreditor.component.GUIUtilities;
import com.cladonia.xngreditor.grammar.FragmentProperties;
import com.cladonia.xngreditor.properties.ConfigurationProperties;
import com.cladonia.xngreditor.properties.KeyPreferences;
import com.cladonia.xngreditor.properties.Keystroke;
import com.cladonia.xngreditor.properties.TextPreferences;

/**
 * The editor for an eXchaNGeR document.
 *
 * @version   $Revision: 1.73 $, $Date: 2005/08/09 14:32:31 $
 * @author Dogsbay
 */
public class Editor extends ViewPanel
        implements CaretListener, UndoableEditListener, DocumentListener, ExchangerDocumentListener {

    private static final boolean DEBUG = false;
    private static final ImageIcon ICON = XngrImageLoader.get()
            .getImage("com/cladonia/xml/editor/icons/EditorIcon.gif");
    private static final String[] XSD_SIMPLE_TYPES = { "anyURI", "base64Binary", "boolean", "byte", "date",
            "dateTime", "decimal", "double", "duration", "ENTITIES", "ENTITY", "float", "gDay", "gMonth",
            "gMonthDay", "gYear", "gYearMonth", "hexBinary", "ID", "IDREF", "IDREFS", "int", "integer", "list",
            "long", "Name", "NCName", "negativeInteger", "NMTOKEN", "NMTOKENS", "nonNegativeInteger",
            "nonPositiveInteger", "normalizedString", "NOTATION", "positiveInteger", "QName", "short", "string",
            "time", "token", "union", "unsignedByte", "unsignedInt", "unsignedLong", "unsignedShort" };
    private static Vector declarationNames = null; // !DOCTYPE, !ELEMENT, !ATTLIST, !ENTITY, !NOTATION
    private static Vector elementDeclarationTypes = null; // #PCDATA, EMPTY, ANY 
    private static Vector entityDeclarationTypes = null; // SYSTEM, PUBLIC, NDATA
    private static Vector attlistDeclarationAll = null; // CDATA, NMTOKEN, NMTOKENS, ID, IDREF, IDREFS, ENTITY, ENTITIES, NOTATION
    private static Vector attlistDeclarationTypes = null; // CDATA, NMTOKEN, NMTOKENS, ID, IDREF, IDREFS, ENTITY, ENTITIES, NOTATION
    private static Vector attlistDeclarationDefaults = null; // #REQUIRED, #IMPLIED, #FIXED
    private static Vector doctypeDeclarationTypes = null; // SYSTEM, PUBLIC
    private static Vector notationDeclarationTypes = null; // SYSTEM, PUBLIC
    private Vector bookmarks = null;
    private Vector fragments = null;
    private boolean hasLatest = false;
    private boolean updateCaret = false;
    private PopupListener popupListener = null;
    private Pattern pattern = null;
    private ErrorList errors = null;
    private EditorPanel topEditor = null;
    private EditorPanel bottomEditor = null;
    private EditorPanel selectedEditor = null;
    private JToolBar fragmentToolbar = null;
    private JSplitPane split = null;
    private EditorProperties properties = null;
    private ConfigurationProperties props = null;
    private ExchangerEditor parent = null;
    private ExchangerView view = null;
    private JPopupMenu popup = null;
    private NameSelectionPopup selectionPopup = null;
    private static FragmentDialog fragmentDialog = null;
    private ExchangerDocument document = null;
    private Tag currentTag = null;
    private Tag parentStartTag = null;
    private Vector tagTree = null;
    private Vector globalElements = null;
    private Vector allElements = null;
    private Vector schemas = null;
    private Vector namespaces = null;
    private Vector elementNames = null;
    private Hashtable attributeNames = null;
    private Vector entityNames = null;
    private boolean insertHappened = false;
    private boolean caretUpdated = false;
    private boolean keyReleased = true;
    private AbstractAction selectAll = null;
    private AbstractAction tabAction = null;
    private AbstractAction unindentAction = null;
    private AbstractAction endTagAction = null;
    private AbstractAction startTagAction = null;
    private AbstractAction previousAttributeAction = null;
    private AbstractAction nextAttributeAction = null;
    private String downKey = null;
    private String upKey = null;
    private String enterKey = null;
    private String escapeKey = null;
    private Examiner examiner = null;
    private ValuesPopupListener valuesPopupListener = null;
    private AttributesPopupListener attributesPopupListener = null;
    private ElementsPopupListener elementsPopupListener = null;

    /**
     * Constructs an editor for the document.
     *
     * @param parent the ExchangerEditor component.
     * @param props the properties for the editor.
     */
    public Editor(ExchangerEditor _parent, ConfigurationProperties props, ExchangerView _view, ErrorList errors) {

        super(new BorderLayout());
        examiner = new Examiner();
        examiner.start();
        this.errors = errors;
        this.props = props;
        this.properties = props.getEditorProperties();
        this.parent = _parent;
        this.view = _view;
        popup = getPopupMenu();
        selectionPopup = new NameSelectionPopup(this);
        selectionPopup.addPropertyChangeListener(new PropertyChangeListener() {

            public void propertyChange(PropertyChangeEvent e) {

                //System.out.println("PropertyChangeListener.propertyChange( "+e.getPropertyName()+")");
                if (selectionPopup.isVisible()) {
                    getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                            .put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "tagcomplete-down");
                    getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                            .put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "tagcomplete-up");
                    getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                            .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "tagcomplete-enter");
                    getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                            .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "tagcomplete-cancel");
                } else {
                    getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                            .put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), downKey);
                    getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                            .put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), upKey);
                    getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                            .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), enterKey);
                    getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                            .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), escapeKey);
                }
            }
        });
        popupListener = new PopupListener() {

            public void popupTriggered(MouseEvent e) {

                showPopupMenu(e);
            }
        };
        tabAction = new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                Object source = event.getSource();
                if (source instanceof EditorPanel.XmlEditor) {
                    ((EditorPanel.XmlEditor) source).indentSelectedText();
                }
            }
        };
        startTagAction = new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                Object source = event.getSource();
                if (source instanceof EditorPanel.XmlEditor) {
                    ((EditorPanel.XmlEditor) source).gotoStartTag();
                }
            }
        };
        endTagAction = new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                Object source = event.getSource();
                if (source instanceof EditorPanel.XmlEditor) {
                    ((EditorPanel.XmlEditor) source).gotoEndTag();
                }
            }
        };
        nextAttributeAction = new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                Object source = event.getSource();
                if (source instanceof EditorPanel.XmlEditor) {
                    ((EditorPanel.XmlEditor) source).gotoNextAttributeValue();
                }
            }
        };
        previousAttributeAction = new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                Object source = event.getSource();
                if (source instanceof EditorPanel.XmlEditor) {
                    ((EditorPanel.XmlEditor) source).gotoPreviousAttributeValue();
                }
            }
        };
        unindentAction = new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                Object source = event.getSource();
                if (source instanceof EditorPanel.XmlEditor) {
                    ((EditorPanel.XmlEditor) source).unindentSelectedText();
                }
            }
        };
        // the select all action (needed for emacs keys)
        selectAll = new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                if (parent != null) {
                    if (parent.getView() != null) {
                        parent.getView().getEditor().getEditor().selectAll();
                        parent.getView().getEditor().setFocus();
                    }
                }
            }
        };
        bookmarks = new Vector();
        topEditor = createEditorPanel(false);
        topEditor.getEditor().setName("Top Panel");
        topEditor.setVisible(false);
        topEditor.setMinimumSize(new Dimension(0, 0));
        bottomEditor = createEditorPanel(true);
        bottomEditor.getEditor().setName("Bottom Panel");
        topEditor.setOther(bottomEditor);
        bottomEditor.setOther(topEditor);
        selectedEditor = bottomEditor;
        split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topEditor, bottomEditor);
        split.setResizeWeight(0);
        //      if ( split.getDividerSize() > 6) {
        split.setDividerSize(2);
        //      }
        Object ui = split.getUI();
        if (ui instanceof BasicSplitPaneUI) {
            ((BasicSplitPaneUI) ui).getDivider().setBorder(
                    new CompoundBorder(new MatteBorder(1, 0, 0, 0, UIManager.getColor("controlDkShadow")),
                            new MatteBorder(1, 0, 0, 0, Color.white)));
            ((BasicSplitPaneUI) ui).getDivider().addMouseListener(new MouseAdapter() {

                //         split.addMouseListener( new MouseAdapter() {
                public void mouseReleased(MouseEvent event) {

                    if (!topEditor.isInitialised()) {
                        topEditor.initialise();
                    }
                    topEditor.setVisible(true);
                }

                public void mouseDragged(MouseEvent event) {

                    if (!topEditor.isInitialised()) {
                        topEditor.initialise();
                    }
                    topEditor.setVisible(true);
                }

                public void mousePressed(MouseEvent event) {

                    if (!topEditor.isInitialised()) {
                        topEditor.initialise();
                    }
                    topEditor.setVisible(true);
                }
            });
            ((BasicSplitPaneUI) ui).getDivider().addMouseListener(new DoubleClickListener() {

                public void doubleClicked(MouseEvent event) {

                    if (topEditor.isVisible()) {
                        topEditor.setVisible(false);
                    }
                }
            });
        }
        split.setBorder(null);
        split.setDividerLocation(0);
        add(getFragmentToolbar(), BorderLayout.WEST);
        add(split, BorderLayout.CENTER);
        updatePreferences();
    }

    private EditorPanel createEditorPanel(boolean init) {

        final EditorPanel editorPanel = new EditorPanel(this, props, init);
        final XmlEditorPane editor = editorPanel.getEditor();
        editor.setEditable(true);
        editor.addMouseListener(popupListener);
        editor.addKeyListener(new KeyAdapter() {

            public void keyPressed(KeyEvent e) {

                if ((e.getKeyCode() == KeyEvent.VK_UP) || (e.getKeyCode() == KeyEvent.VK_DOWN)
                        || (e.getKeyCode() == KeyEvent.VK_LEFT) || (e.getKeyCode() == KeyEvent.VK_RIGHT)
                        || (e.getKeyCode() == KeyEvent.VK_PAGE_DOWN) || (e.getKeyCode() == KeyEvent.VK_PAGE_UP)) {
                    keyReleased = false;
                }
            }

            public void keyReleased(KeyEvent e) {

                keyReleased = true;
                updatePositionalStuff();
            }
        });
        editor.addFocusListener(new FocusListener() {

            public void focusGained(FocusEvent e) {

                //            System.out.println( "["+document.getName()+"] FocusListener.focusGained()");
                if (editor != null) {
                    selectedEditor = editorPanel;
                    if (parent != null) {
                        view.setFocussed();
                        updateHelper();
                    }
                }
            }

            public void focusLost(FocusEvent e) {

                //            System.out.println( "["+document.getName()+"] FocusListener.focusLost()");
            }
        });
        editor.setCaret(new XmlCaret());
        editor.addCaretListener(this);
        //      DropTarget target = new XMLDropTarget( editor.getDropTarget());
        //      editor.setDropTarget( target);
        // >>> Keymap...
        editor.getActionMap().put("tagcomplete-up", new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                selectionPopup.selectPrevious();
            }
        });
        editor.getActionMap().put("tagcomplete-down", new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                selectionPopup.selectNext();
            }
        });
        editor.getActionMap().put("tagcomplete-enter", new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                insertCurrentSelectedName();
            }
        });
        editor.getActionMap().put("tagcomplete-cancel", new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                hideSelectionPopup();
            }
        });
        editor.getActionMap().put("xngr-indent", tabAction);
        editor.getActionMap().put("xngr-unindent", unindentAction);
        editor.getActionMap().put("gotoStartTag", startTagAction);
        editor.getActionMap().put("gotoEndTag", endTagAction);
        editor.getActionMap().put("gotoPreviousAttributeValue", previousAttributeAction);
        editor.getActionMap().put("gotoNextAttributeValue", nextAttributeAction);
        editor.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,
                Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false), "tagcomplete-popup");
        editor.getActionMap().put("tagcomplete-popup", new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                Object source = event.getSource();
                if (source instanceof EditorPanel.XmlEditor) {
                    ((EditorPanel.XmlEditor) source).promptText();
                }
            }
        });
        editor.getInputMap()
                .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
                        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + InputEvent.SHIFT_MASK, false),
                        "toggle-full-fold");
        editor.getActionMap().put("toggle-full-fold", new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                Object source = event.getSource();
                if (source instanceof EditorPanel.XmlEditor) {
                    int pos = ((EditorPanel.XmlEditor) source).getCaretPosition();
                    int line = ((EditorPanel.XmlEditor) source).getDocument().getDefaultRootElement()
                            .getElementIndex(pos);
                    ((EditorPanel.XmlEditor) source).getFoldingMargin().toggleFullFold(line);
                }
            }
        });
        editor.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
                Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false), "toggle-fold");
        editor.getActionMap().put("toggle-fold", new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                Object source = event.getSource();
                if (source instanceof EditorPanel.XmlEditor) {
                    int pos = ((EditorPanel.XmlEditor) source).getCaretPosition();
                    int line = ((EditorPanel.XmlEditor) source).getDocument().getDefaultRootElement()
                            .getElementIndex(pos);
                    ((EditorPanel.XmlEditor) source).getFoldingMargin().toggleFold(line);
                }
            }
        });
        editor.getInputMap().put(
                KeyStroke.getKeyStroke(KeyEvent.VK_F6, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false),
                "toggle-split");
        editor.getActionMap().put("toggle-split", new AbstractAction() {

            public void actionPerformed(ActionEvent event) {

                if (topEditor.getSize().height > 0 && bottomEditor.getSize().height > 0) {
                    if (selectedEditor == topEditor) {
                        bottomEditor.setFocus();
                    } else {
                        topEditor.setFocus();
                    }
                }
                if (topEditor.getSize().height <= 5) {
                    if (!topEditor.isInitialised()) {
                        topEditor.initialise();
                        topEditor.setVisible(true);
                    }
                    split.setDividerLocation((double) 0.5);
                    scrollCursorToVisible();
                }
            }
        });
        editor.addMouseMotionListener(new MouseMotionListener() {

            boolean dragged = false;

            public void mouseMoved(MouseEvent e) {

                if (dragged) {
                    SwingUtilities.invokeLater(new Runnable() {

                        public void run() {

                            editor.getCaret().setVisible(true);
                        }
                    });
                }
                dragged = false;
            }

            public void mouseDragged(MouseEvent e) {

                dragged = true;
            }
        });
        return editorPanel;
    }

    public void updateCaretManual(boolean manual) {

        updateCaret = manual;
    }

    //  >> DocumentListener
    public void changedUpdate(DocumentEvent event) {

        //      System.out.println( "DocumentListener.changedUpdate( "+event+")");
        insertHappened = false;
        if (updateCaret) {
            setCursorPosition(event.getOffset());
        }
        updateFolds();
    }

    public void insertUpdate(DocumentEvent event) {

        //      System.out.println( "DocumentListener.insertUpdate( "+event+")");
        if (event.getLength() <= 1) {
            insertHappened = true;
        } else {
            insertHappened = false;
        }
        if (updateCaret) {
            setCursorPosition(event.getOffset());
        }
        updateFolds();
    }

    int previousFoldLines = 0;

    private void updateFolds() {

        if (getLines() != previousFoldLines) {
            previousFoldLines = getLines();
            topEditor.getFoldingMargin().checkFolds();
            bottomEditor.getFoldingMargin().checkFolds();
        }
    }

    public void removeUpdate(DocumentEvent event) {

        insertHappened = false;
        if (updateCaret) {
            setCursorPosition(event.getOffset());
        }
        updateFolds();
    }

    // <<< DocumentListener
    public void initBookmarks(Vector bookms) {

        Vector bms = new Vector(bookms);
        this.bookmarks = new Vector();
        if (document.getURL() != null) {
            for (int i = 0; i < bms.size(); i++) {
                Bookmark bm = (Bookmark) bms.elementAt(i);
                if (bm.getURL() != null && bm.getURL().equals(document.getURL().toString())) {
                    int line = bm.getLineNumber();
                    Element root = getEditor().getDocument().getDefaultRootElement();
                    Element value = root.getElement(line);
                    if (value != null) {
                        bm.init(value, document);
                        bookmarks.addElement(bm);
                    } else {
                        // does no longer exist in this document, remove!
                        parent.removeBookmark(bm);
                    }
                }
            }
        }
    }

    public void resetBookmarks() {

        Vector bms = new Vector(bookmarks);
        for (int i = 0; i < bms.size(); i++) {
            Bookmark bm = (Bookmark) bms.elementAt(i);
            if (!bm.isRemoved()) {
                int line = bm.getLineNumber();
                Element value = null;
                if (line != -1) {
                    Element root = getEditor().getDocument().getDefaultRootElement();
                    value = root.getElement(line);
                }
                if (value != null) {
                    bm.init(value, document);
                } else {
                    // does no longer exist in this document, remove!
                    parent.removeBookmark(bm);
                    bookmarks.removeElement(bm);
                }
            } else {
                bookmarks.removeElement(bm);
            }
        }
    }

    public void updateBookmarks() {

        for (int i = 0; i < bookmarks.size(); i++) {
            ((Bookmark) bookmarks.elementAt(i)).update();
        }
    }

    /**
     * Gets the editor icon
     *
     * @return the icon for the editor.
     */
    public ImageIcon getIcon() {

        return ICON;
    }

    /**
     * Paste what ever is on the clipboard in the editor pane.
     */
    public void paste() {

        getEditor().paste();
    }

    /**
     * Update the preferences.
     */
    public void updatePreferences() {

        topEditor.updatePreferences();
        bottomEditor.updatePreferences();
        selectionPopup.setPreferredFont(TextPreferences.getBaseFont());
        showFragmentToolbar(properties.isShowFragmentsToolbar());
        this.revalidate();
        this.repaint();
        // need to set up the keymappings
        String activeConfig = props.getKeyPreferences().getActiveConfiguration();
        setKeyMappings(parent, activeConfig);
    }

    public void scrollCursorToVisible() {

        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                if (topEditor.isInitialised()) {
                    topEditor.gotoCursor();
                }
                bottomEditor.gotoCursor();
            }
        });
    }

    public void showFragmentToolbar(boolean visible) {

        if (fragments != null && fragments.size() > 0) {
            fragmentToolbar.setVisible(properties.isShowFragmentsToolbar());
        } else {
            fragmentToolbar.setVisible(false);
        }
    }

    public void setEndTagCompletion(boolean enabled) {

        topEditor.setEndTagCompletion(enabled);
        bottomEditor.setEndTagCompletion(enabled);
    }

    public void setSmartIndentation(boolean enabled) {

        topEditor.setSmartIndentation(enabled);
        bottomEditor.setSmartIndentation(enabled);
    }

    public void showLinenumberMargin(boolean visible) {

        topEditor.showLinenumberMargin(visible);
        bottomEditor.showLinenumberMargin(visible);
    }

    public void showOverviewMargin(boolean visible) {

        topEditor.showOverviewMargin(visible);
        bottomEditor.showOverviewMargin(visible);
    }

    public void showFoldingMargin(boolean visible) {

        topEditor.showFoldingMargin(visible);
        bottomEditor.showFoldingMargin(visible);
    }

    public void showAnnotationMargin(boolean visible) {

        topEditor.showAnnotationMargin(visible);
        bottomEditor.showAnnotationMargin(visible);
    }

    private void turnOffCtrlX() {

        // remove Ctrl-X from inputmap as needed for alternative editing mode
        KeyStroke ctrlX = KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK, false);
        InputMap im = topEditor.getEditor().getInputMap();
        InputMap pem = im;
        while (pem != null) {
            pem.remove(ctrlX);
            pem = pem.getParent();
        }
        im = bottomEditor.getEditor().getInputMap();
        pem = im;
        while (pem != null) {
            pem.remove(ctrlX);
            pem = pem.getParent();
        }
    }

    /**
     *  sets all the keymappings for the specified configuation
     *
     * @param parent The ExchangerEditor
     * @param configName The configuration name 
     */
    public void setKeyMappings(ExchangerEditor parent, String configName) {

        if (configName.equalsIgnoreCase(KeyPreferences.EMACS)) {
            // turn off Ctrl-X for each editor as that will now be used by emacs editing mode
            turnOffCtrlX();
        }
        KeyPreferences pref = props.getKeyPreferences();
        Hashtable keyMap = pref.getKeyMapElements(configName);
        Enumeration actionNames = keyMap.keys();
        while (actionNames.hasMoreElements()) {
            String actionName = (String) actionNames.nextElement();
            XElement keymap = (XElement) keyMap.get(actionName);
            Vector keystrokes = pref.getKeystrokes(keymap);
            Keystroke keystroke = null;
            Keystroke keystroke2 = null;
            int keystrokeSize = keystrokes.size();
            if (keystrokeSize == 1) {
                keystroke = (Keystroke) keystrokes.get(0);
            } else if (keystrokeSize == 2) {
                keystroke = (Keystroke) keystrokes.get(0);
                keystroke2 = (Keystroke) keystrokes.get(1);
            } else {
                // there are no keys assigned for this action, so remove action from map
            }
            if (actionName.equals(KeyPreferences.SELECT_ALL_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setSelectAllActionKey(pref.getKeyStroke(keystroke));
                } else if (keystrokeSize == 2) {
                    //   add the second keystroke to the mode's map
                    Action action = selectAll;
                    KeyStroke stroke = pref.getKeyStroke(keystroke2);
                    parent.getStatusbar().addToModeMap(KeyPreferences.SELECT_ALL_ACTION, stroke, action);
                } else {
                    // blank the action
                    setSelectAllActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.TAB_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setTabActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setTabActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.UNINDENT_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setUnindentActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setUnindentActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.UP_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setUpActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setUpActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.DOWN_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setDownActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setDownActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.RIGHT_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setRightActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setRightActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.LEFT_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setLeftActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setLeftActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.PAGE_UP_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setPageUpActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setPageUpActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.PAGE_DOWN_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setPageDownActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setPageDownActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.BEGIN_LINE_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setBeginLineActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setBeginLineActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.END_LINE_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setEndLineActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setEndLineActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.BEGIN_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setBeginActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setBeginActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.END_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setEndActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setEndActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.PREVIOUS_WORD_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setPreviousWordActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setPreviousWordActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.NEXT_WORD_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setNextWordActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setNextWordActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.DELETE_NEXT_CHAR_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setDeleteNextCharActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setDeleteNextCharActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.DELETE_PREV_CHAR_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setDeletePrevCharActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setDeletePrevCharActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.GOTO_START_TAG_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setGoToStartTagActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setGoToStartTagActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.GOTO_END_TAG_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setGoToEndTagActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setGoToEndTagActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.GOTO_NEXT_ATTRIBUTE_VALUE_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setGoToNextAttributeValueActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setGoToNextAttributeValueActionKey(null);
                }
            } else if (actionName.equals(KeyPreferences.GOTO_PREVIOUS_ATTRIBUTE_VALUE_ACTION)) {
                // update the begin line action
                if (keystrokeSize == 1) {
                    // only a single keystroke
                    setGoToPreviousAttributeValueActionKey(pref.getKeyStroke(keystroke));
                } else {
                    // blank the action
                    setGoToPreviousAttributeValueActionKey(null);
                }
            }
        }
        downKey = (String) getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                .get(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false));
        upKey = (String) getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                .get(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false));
        enterKey = (String) getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                .get(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false));
        escapeKey = (String) getEditor().getInputMap(JComponent.WHEN_FOCUSED)
                .get(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false));
    }

    private void setSelectAllActionKey(KeyStroke stroke) {

        removePreviousMapping("select-all");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "select-all");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "select-all");
    }

    private void setCutActionKey(KeyStroke stroke) {

        removePreviousMapping("cut-to-clipboard");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "cut-to-clipboard");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "cut-to-clipboard");
    }

    private void setTabActionKey(KeyStroke stroke) {

        removePreviousMapping("xngr-indent");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "xngr-indent");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "xngr-indent");
    }

    private void setUnindentActionKey(KeyStroke stroke) {

        removePreviousMapping("xngr-unindent");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "xngr-unindent");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "xngr-unindent");
    }

    private void setGoToStartTagActionKey(KeyStroke stroke) {

        removePreviousMapping2("gotoStartTag");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "gotoStartTag");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "gotoStartTag");
    }

    private void setGoToPreviousAttributeValueActionKey(KeyStroke stroke) {

        removePreviousMapping2("gotoPreviousAttributeValue");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "gotoPreviousAttributeValue");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "gotoPreviousAttributeValue");
    }

    private void setGoToNextAttributeValueActionKey(KeyStroke stroke) {

        removePreviousMapping2("gotoNextAttributeValue");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "gotoNextAttributeValue");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "gotoNextAttributeValue");
    }

    private void setGoToEndTagActionKey(KeyStroke stroke) {

        removePreviousMapping2("gotoEndTag");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "gotoEndTag");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "gotoEndTag");
    }

    private void setUpActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-up");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-up");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-up");
    }

    private void setDownActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-down");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-down");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-down");
    }

    private void setRightActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-forward");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-forward");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-forward");
    }

    private void setLeftActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-backward");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-backward");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-backward");
    }

    private void setPageUpActionKey(KeyStroke stroke) {

        removePreviousMapping2("page-up");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "page-up");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "page-up");
    }

    private void setPageDownActionKey(KeyStroke stroke) {

        removePreviousMapping2("page-down");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "page-down");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "page-down");
    }

    private void setBeginLineActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-begin-line");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-begin-line");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-begin-line");
    }

    private void setEndLineActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-end-line");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-end-line");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-end-line");
    }

    private void setBeginActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-begin");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-begin");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-begin");
    }

    private void setEndActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-end");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-end");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-end");
    }

    private void setPreviousWordActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-previous-word");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-previous-word");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-previous-word");
    }

    private void setNextWordActionKey(KeyStroke stroke) {

        removePreviousMapping2("caret-next-word");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-next-word");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "caret-next-word");
    }

    private void setDeleteNextCharActionKey(KeyStroke stroke) {

        removePreviousMapping2("delete-next");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "delete-next");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "delete-next");
    }

    private void setDeletePrevCharActionKey(KeyStroke stroke) {

        removePreviousMapping2("delete-previous");
        bottomEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "delete-previous");
        topEditor.getEditor().getInputMap(JComponent.WHEN_FOCUSED).put(stroke, "delete-previous");
    }

    private void removePreviousMapping(String actionName) {

        InputMap im = bottomEditor.getEditor().getInputMap();
        InputMap pem = im;
        while (pem != null) {
            KeyStroke[] strokes = pem.allKeys();
            for (int i = 0; i < strokes.length; i++) {
                String actionMapKey = pem.get(strokes[i]).toString();
                if (actionMapKey != null && actionMapKey.equalsIgnoreCase(actionName)) {
                    pem.remove(strokes[i]);
                }
            }
            pem = pem.getParent();
        }
        im = topEditor.getEditor().getInputMap();
        pem = im;
        while (pem != null) {
            KeyStroke[] strokes = pem.allKeys();
            for (int i = 0; i < strokes.length; i++) {
                String actionMapKey = pem.get(strokes[i]).toString();
                if (actionMapKey != null && actionMapKey.equalsIgnoreCase(actionName)) {
                    pem.remove(strokes[i]);
                }
            }
            pem = pem.getParent();
        }
    }

    // only removes our own custom mappings, not any of the higher inbuilt ones
    private void removePreviousMapping2(String actionName) {

        InputMap im = topEditor.getEditor().getInputMap();
        KeyStroke[] strokes = im.allKeys();
        for (int i = 0; i < strokes.length; i++) {
            String actionMapKey = im.get(strokes[i]).toString();
            if (actionMapKey != null && actionMapKey.equalsIgnoreCase(actionName)) {
                im.remove(strokes[i]);
            }
        }
        im = bottomEditor.getEditor().getInputMap();
        strokes = im.allKeys();
        for (int i = 0; i < strokes.length; i++) {
            String actionMapKey = im.get(strokes[i]).toString();
            if (actionMapKey != null && actionMapKey.equalsIgnoreCase(actionName)) {
                im.remove(strokes[i]);
            }
        }
    }

    //   private FoldingMargin getFoldingMargin() { 
    //      return foldingMargin;
    //   }
    //   
    //   private Margin getMargin() { 
    //      return margin;
    //   }
    //
    public void setWrapping(boolean wrap) {

        topEditor.setWrapping(wrap);
        bottomEditor.setWrapping(wrap);
    }

    public JToolBar getFragmentToolbar() {

        if (fragmentToolbar == null) {
            fragmentToolbar = new JToolBar();
            fragmentToolbar.setRollover(true);
            fragmentToolbar.setFloatable(false);
            fragmentToolbar.setOrientation(JToolBar.VERTICAL);
            fragmentToolbar.setVisible(false);
        }
        return fragmentToolbar;
    }

    public void updateFragmentKeys() {

        removeFragmentKeys();
        if (fragments != null) {
            for (int i = 0; i < fragments.size(); i++) {
                FragmentAction action = (FragmentAction) fragments.elementAt(i);
                // Create a name not used by any other mapping
                String name = "xngr.editor.fragment." + i;
                KeyStroke key = (KeyStroke) action.getValue(Action.ACCELERATOR_KEY);
                if (key != null) {
                    topEditor.getEditor().getActionMap().put(name, action);
                    topEditor.getEditor().getInputMap().put(key, name);
                    bottomEditor.getEditor().getActionMap().put(name, action);
                    bottomEditor.getEditor().getInputMap().put(key, name);
                }
            }
        }
    }

    private void removeFragmentKeys() {

        ActionMap map = getEditor().getActionMap();
        Object keys[] = map.allKeys();
        for (int i = 0; i < keys.length; i++) {
            Object key = keys[i];
            if (key instanceof String && ((String) key).startsWith("xngr.editor.fragment.")) {
                topEditor.getEditor().getActionMap().put(key, null);
                bottomEditor.getEditor().getActionMap().put(key, null);
                removePreviousMapping((String) key);
            }
        }
    }

    public void setFragments(Vector frags) {

        frags = sortFragments(frags);
        fragmentToolbar = getFragmentToolbar();
        fragmentToolbar.removeAll();
        fragments = new Vector();
        if (frags != null && frags.size() > 0) {
            for (int i = 0; i < frags.size(); i++) {
                FragmentProperties props = (FragmentProperties) frags.elementAt(i);
                FragmentAction fragment = new FragmentAction(props);
                fragments.addElement(fragment);
                if (props.getIcon() != null && props.getIcon().length() > 0) {
                    fragmentToolbar.add(fragment);
                }
            }
            if (fragmentToolbar.getComponentCount() > 0) {
                fragmentToolbar.setVisible(properties.isShowFragmentsToolbar());
            } else {
                fragmentToolbar.setVisible(false);
            }
        } else {
            fragmentToolbar.setVisible(false);
        }
        updateFragmentKeys();
    }

    private Vector sortFragments(Vector fragments) {

        Vector result = new Vector();
        for (int i = 0; i < fragments.size(); i++) {
            FragmentProperties fragment = (FragmentProperties) fragments.elementAt(i);
            int index = -1;
            for (int j = 0; j < result.size() && index == -1; j++) {
                // Compare by order
                if (fragment.getOrder() <= ((FragmentProperties) result.elementAt(j)).getOrder()) {
                    index = j;
                }
            }
            if (index != -1) {
                result.insertElementAt(fragment, index);
            } else {
                result.addElement(fragment);
            }
        }
        return result;
    }

    /**
     * Cut what ever is selected in the editor pane to the clipboard.
     */
    public void cut() {

        getEditor().cut();
    }

    /**
     * Copy what ever is selected in the editor pane to the clipboard.
     */
    public void copy() {

        getEditor().copy();
    }

    /**
     * Copy what ever is selected in the editor pane to the clipboard.
     */
    public XmlEditorPane getEditor() {

        if (selectedEditor != null) {
            return selectedEditor.getEditor();
        }
        return null;
    }

    /**
     * Replaces all text in the editor and creates one compound 'UndoableEdit'.
     */
    public void setText(String text) {

        if (DEBUG)
            System.out.println("Editor.setDocument( " + document + ")");
        updateBookmarks();
        view.getChangeManager().startCompound(true);
        getEditor().setText(text);
        getEditor().setCaretPosition(0);
        view.getChangeManager().endCompound();
        resetBookmarks();
    }

    /**
     * Sets the document in the editor.
     *
     * @param document the XML Document.
     */
    public void setDocument(ExchangerDocument document) {

        if (DEBUG)
            System.out.println("Editor.setDocument( " + document + ")");
        updateBookmarks();
        view.getChangeManager().startCompound(false);
        if (this.document != null) {
            bottomEditor.getEditor().getDocument().removeUndoableEditListener(this);
            bottomEditor.getEditor().getDocument().removeDocumentListener(this);
            this.document.removeListener(this);
        }
        this.document = document;
        if (document != null) {
            document.addListener(this);
            if (document.isXML() || document.isDTD()) {
                bottomEditor.getEditor().setContentType("text/xml");
                if (topEditor.isInitialised()) {
                    topEditor.getEditor().setContentType("text/xml");
                }
            } else {
                bottomEditor.getEditor().setContentType("text/txt");
                if (topEditor.isInitialised()) {
                    topEditor.getEditor().setContentType("text/txt");
                }
            }
            XmlDocument doc = (XmlDocument) bottomEditor.getEditor().getDocument();
            doc.addUndoableEditListener(this);
            doc.addDocumentListener(this);
            bottomEditor.getEditor().setText(document.getText());
            if (topEditor.isInitialised()) {
                topEditor.getEditor().setDocument(doc);
            }
            //         topEditor.getEditor().setText( document.getText());
            doc.resetUpdates();
        } else {
            bottomEditor.getEditor().setText("");
        }
        bottomEditor.getEditor().setCaretPosition(0);
        if (topEditor.isInitialised()) {
            topEditor.getEditor().setCaretPosition(0);
        }
        hasLatest = true;
        view.getChangeManager().discardCompound();
        resetBookmarks();
    }

    /**
     * Set the text in the document and report the exceptions.
     */
    public void parse() throws SAXParseException, IOException {

        if (DEBUG)
            System.out.println("Editor.parse()");
        hasLatest = true;
        try {
            document.setText(getEditor().getText(0, getEditor().getDocument().getLength()));
            if (!document.isError()) {
                ((XmlDocument) getEditor().getDocument()).resetUpdates();
            }
        } catch (SAXParseException e) {
            //         e.printStackTrace();
            throw e;
        } catch (final IOException e) {
            //          e.printStackTrace();
            throw e;
        } catch (Exception e) {
            //         e.printStackTrace();
        } finally {
            view.getChangeManager().markParse();
        }
    }

    //   public void replaceSelection( String replacement) {
    //      view.getChangeManager().startCompound( true);
    //      editor.replaceSelection( replacement);
    //      view.getChangeManager().endCompound();
    //   }

    public void replaceSelection(String replacement) {
        view.getChangeManager().startCompound(true);
        getEditor().replaceSelection(replacement);
        view.getChangeManager().endCompound();
    }

    public void replaceAll(String search, String replacement, boolean regExp, boolean matchCase,
            boolean matchword) {

        updateBookmarks();
        view.getChangeManager().startCompound(true);
        if (!regExp) {
            search = "\\Q" + StringUtilities.prepareNonRegularExpression(search) + "\\E";
            replacement = StringUtilities.prepareNonRegularExpressionReplacement(replacement);
        }
        if (matchword) {
            search = "\\b" + search + "\\b";
        }
        try {
            if (!matchCase) {
                pattern = Pattern.compile(search, Pattern.CASE_INSENSITIVE);
            } else {
                pattern = Pattern.compile(search);
            }
        } catch (PatternSyntaxException ex) {
            parent.setStatus("Invalid Regular Expression \"" + search + "\"!");
            return;
        }
        try {
            int caret = getEditor().getCaretPosition();
            Matcher matcher = pattern.matcher(getEditor().getText(0, getEditor().getDocument().getLength()));
            String text = matcher.replaceAll(replacement);
            getEditor().setText(text);
            getEditor().setCaretPosition(caret);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            view.getChangeManager().endCompound();
            resetBookmarks();
        }
    }

    public void replace(Matcher matcher, String replacement, boolean regExp, boolean down) {

        updateBookmarks();
        getEditor().select(matcher.start(), matcher.end());
        if (regExp) {
            StringBuffer sb = new StringBuffer();
            int start = matcher.start();
            matcher.appendReplacement(sb, replacement);
            int end = matcher.end();
            replacement = sb.substring(start);
        }
        view.getChangeManager().startCompound(true);
        try {
            getEditor().replaceSelection(replacement);
            if (!down) { // going up..
                getEditor().setCaretPosition(getEditor().getCaretPosition() - replacement.length());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            view.getChangeManager().endCompound();
            resetBookmarks();
        }
    }

    public Matcher search(String xpath, String search, boolean regExp, boolean matchCase, boolean matchword,
            boolean down, boolean wrap) {

        Vector nodes = null;
        Vector ranges = new Vector();
        try {
            if (xpath != null && xpath.trim().length() > 0) {
                nodes = document.search(xpath);
            }
        } catch (Exception e) {
            parent.setStatus("Invalid XPath \"" + xpath + "\"!");
            return null;
        }
        if (nodes != null) {
            for (int i = 0; i < nodes.size(); i++) {
                Node node = (Node) nodes.elementAt(i);
                Range range = null;
                if (node instanceof XElement) {
                    range = new Range((XElement) node);
                } else if (node instanceof XAttribute) {
                    range = new Range((XAttribute) node);
                } else {
                    parent.setStatus("Invalid Node Type \"" + node.getNodeTypeName() + "\"!");
                    return null;
                    //               range = new Range( (XElement)node.getParent());
                }
                addRange(ranges, range);
            }
        } else {
            ranges.addElement(new Range(0, getEditor().getDocument().getLength()));
        }
        Matcher matcher = null;
        try {
            matcher = getEditor().search(ranges, search, regExp, matchCase, matchword, down, wrap);
        } catch (PatternSyntaxException ex) {
            parent.setStatus("Invalid Regular Expression \"" + search + "\"!");
            return null;
        }
        if (matcher != null) {
            parent.setStatus("Search complete.");
        } else {
            parent.setStatus("String \"" + search + "\" not found!");
        }
        return matcher;
    }

    private void addRange(Vector ranges, Range range) {

        Vector oldRanges = new Vector(ranges);
        for (int i = 0; i < oldRanges.size(); i++) {
            Range r = (Range) oldRanges.elementAt(i);
            if (r.contains(range)) {
                // do not add
                return;
            } else if (range.contains(r)) {
                // remove previous ranges
                ranges.removeElement(r);
            }
        }
        oldRanges = new Vector(ranges);
        for (int i = 0; i < oldRanges.size(); i++) {
            Range r = (Range) oldRanges.elementAt(i);
            if (r.getStart() > range.getStart()) {
                ranges.insertElementAt(range, i);
                return;
            }
        }
        ranges.addElement(range);
    }

    /**
     * Perform a search in the text.
     *
     * @param search the text to search for.
     * @param matchcase should the search match the case.
     * @param search down/upward from caret the position.
     */
    //   public Matcher search( String search, boolean regExp, boolean matchCase, boolean matchword, boolean down, boolean wrap) {
    //      if (DEBUG) System.out.println( "Editor.search( "+search+", "+matchCase+", "+down+")");
    //
    //      Matcher matcher = editor.search( search, regExp, matchCase, matchword, down, wrap);
    //
    //      if ( matcher != null) {
    //         parent.setStatus( "Search complete");
    //      } else {
    //         parent.setStatus( "String \""+search+"\" not found!");
    //      }
    //      
    //      return matcher;
    //   }
    /**
     * Set the focus on the editor component!
     */
    public void setFocus() {

        if (!getEditor().hasFocus()) {
            getEditor().requestFocusInWindow();
        }
    }

    /**
     * Selects text associated with the element.
     *
     * @param element the element to select the text for.
     */
    public void selectElement(XElement element) {

        selectElement(element, false, -1);
    }

    public void selectElement(XElement element, boolean endTag, int y) {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        if (!endTag) {
            int start = doc.calculateNewPosition(element.getElementStartPosition());
            if (start != -1) {
                Tag tag = doc.getCurrentTag(start + 1);
                if (tag != null) {
                    getEditor().select(tag.getStart(), tag.getEnd());
                }
            }
        } else {
            int end = doc.calculateNewPosition(element.getElementEndPosition());
            if (end != -1) {
                Tag tag = doc.getCurrentTag(end - 1);
                if (tag != null && tag.getType() == Tag.END_TAG) {
                    getEditor().select(tag.getStart(), tag.getEnd());
                }
            }
        }
        if (selectedEditor == bottomEditor) {
            y = y - (topEditor.getSize().height + split.getDividerSize());
        }
        if (y >= 0) {
            try {
                Rectangle r = getEditor().getVisibleRect();
                Rectangle sr = getEditor().modelToView(getEditor().getSelectionStart());
                sr.height = r.height;
                sr.y = sr.y - y;
                if (r.height > y && sr.y >= 0) {
                    getEditor().scrollRectToVisible(sr);
                }
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
        }
    }

    public void selectError(XMLError error) {

        if (error != null && error.getLineNumber() > 0) {
            selectedEditor.selectError(error);
            //         XmlDocument doc = (XmlDocument)getEditor().getDocument();
            //         Element element = doc.getDefaultRootElement().getElement( error.getLineNumber()-1);
            //         int pos = element.getStartOffset()+(error.getColumnNumber()-1);
            //
            //         if ( Character.isWhitespace( doc.getLastCharacter( pos))) {
            //            getEditor().select( pos, pos+1);
            //         } else {
            //            getEditor().select( pos-1, pos);
            //         }
            //         
            //         parent.getOutputPanel().selectError( error);
        }
    }

    public void updateError(XMLError error) {

        if (error != null && error.getLineNumber() > 0) {
            parent.getOutputPanel().selectError(error);
        }
    }

    /**
     * Selects text associated with the attribute.
     *
     * @param attribute the attribute to select the text for.
     */
    public void selectAttribute(XAttribute attribute, int y) {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        int start = doc.calculateNewPosition(attribute.getAttributeStartPosition());
        int end = doc.calculateNewPosition(attribute.getAttributeEndPosition());
        if (start != -1 && end != -1) {
            getEditor().select(start, end);
        }
        if (selectedEditor == bottomEditor) {
            y = y - (topEditor.getSize().height + split.getDividerSize());
        }
        if (y >= 0) {
            try {
                Rectangle r = getEditor().getVisibleRect();
                Rectangle sr = getEditor().modelToView(getEditor().getSelectionStart());
                sr.height = r.height;
                sr.y = sr.y - y;
                if (r.height > y && sr.y >= 0) {
                    getEditor().scrollRectToVisible(sr);
                }
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Goto the start of a specific line in the document.
     *
     * @param line the line to go to.
     */
    public void gotoLine(int line) {

        getEditor().gotoLine(line);
    }

    private void showPopupMenu(MouseEvent e) {

        String selectedText = getEditor().getSelectedText();
        JPopupMenu popup = new JPopupMenu();
        if (selectedText != null) {
            if (selectedText.length() > 20) {
                selectedText = selectedText.substring(0, 17);
                selectedText = selectedText + "...";
            }
            URL url = getCurrentURL();
            if (url != null) {
                popup.add(new WrapperAction(parent.getOpenCurrentURLAction(),
                        "Open \"" + URLUtilities.toDisplay(url) + "\""));
                popup.addSeparator();
            }
            popup.add(new WrapperAction(parent.getFindAction(), "Find \"" + selectedText + "\""));
            popup.addSeparator();
            boolean separator = false;
            Action toggleEmptyElementAction = parent.getToggleEmptyElementAction();
            if (toggleEmptyElementAction.isEnabled()) {
                popup.add(new WrapperAction(toggleEmptyElementAction, "Expand Empty Element"));
                separator = true;
            }
            Action tagAction = parent.getTagAction();
            if (tagAction.isEnabled()) {
                popup.add(new WrapperAction(tagAction, "Tag Selection"));
                separator = true;
            }
            Action commentAction = parent.getCommentAction();
            if (commentAction.isEnabled()) {
                popup.add(new WrapperAction(commentAction, commentAction.getValue(Action.NAME) + " Selection"));
                separator = true;
            }
            Action cdataAction = parent.getCDATAAction();
            if (cdataAction.isEnabled()) {
                popup.add(new WrapperAction(cdataAction, cdataAction.getValue(Action.NAME) + " Selection"));
                separator = true;
            }
            if (separator) {
                popup.addSeparator();
            }
            popup.add(parent.getSubstituteCharactersAction());
            popup.add(parent.getSubstituteEntitiesAction());
            popup.add(parent.getStripTagsAction());
            popup.addSeparator();
            popup.add(parent.getParseAction());
            popup.add(parent.getValidateAction());
            popup.addSeparator();
            popup.add(parent.getCutAction());
            popup.add(parent.getCopyAction());
            popup.add(parent.getPasteAction());
            popup.addSeparator();
            popup.add(parent.getSaveAction());
            popup.add(parent.getSaveAsAction());
            popup.addSeparator();
            popup.add(parent.getCloseAction());
        } else {
            int pos = getEditor().viewToModel(new Point(e.getX(), e.getY()));
            getEditor().setCaretPosition(pos);
            // need specifically the tag at the current position and don't care about the tree!
            Tag tag = ((XmlDocument) getEditor().getDocument()).getCurrentTag(pos);
            Tag parentTag = ((XmlDocument) getEditor().getDocument()).getParentStartTag(pos);
            String currentText = getCurrentText();
            URL url = getCurrentURL();
            if (url != null) {
                popup.add(new WrapperAction(parent.getOpenCurrentURLAction(),
                        "Open \"" + URLUtilities.toDisplay(url) + "\""));
                popup.addSeparator();
            }
            if (currentText != null) {
                if (currentText.length() > 20) {
                    currentText = currentText.substring(0, 17);
                    currentText = currentText + "...";
                }
                popup.add(new WrapperAction(parent.getFindAction(), "Find \"" + currentText + "\""));
                popup.addSeparator();
            }
            if (tag != null) {
                if (tag.getType() == Tag.COMMENT_TAG) {
                    popup.add(parent.getCommentAction());
                    popup.addSeparator();
                } else if (tag.getType() == Tag.CDATA_TAG) {
                    popup.add(parent.getCDATAAction());
                    popup.addSeparator();
                } else if (tag.getType() == Tag.START_TAG) {
                    popup.add(new WrapperAction(parent.getGotoEndTagAction(),
                            "Goto \"" + tag.getQualifiedName() + "\" End Tag"));
                    popup.addSeparator();
                    popup.add(new WrapperAction(parent.getSelectElementAction(),
                            "Select \"" + tag.getQualifiedName() + "\" Element"));
                    popup.add(new WrapperAction(parent.getSelectElementContentAction(),
                            "Select \"" + tag.getQualifiedName() + "\" Element Content"));
                    popup.addSeparator();
                } else if (tag.getType() == Tag.EMPTY_TAG) {
                    popup.add(new WrapperAction(parent.getSelectElementAction(),
                            "Select \"" + tag.getQualifiedName() + "\" Element"));
                    popup.addSeparator();
                } else if (tag.getType() == Tag.END_TAG) {
                    popup.add(new WrapperAction(parent.getGotoStartTagAction(),
                            "Goto \"" + tag.getQualifiedName() + "\" Start Tag"));
                    popup.addSeparator();
                    popup.add(new WrapperAction(parent.getSelectElementAction(),
                            "Select \"" + tag.getQualifiedName() + "\" Element"));
                    popup.add(new WrapperAction(parent.getSelectElementContentAction(),
                            "Select \"" + tag.getQualifiedName() + "\" Element Content"));
                    popup.addSeparator();
                }
            } else if (parentTag != null) {
                popup.add(new WrapperAction(parent.getGotoStartTagAction(),
                        "Goto \"" + parentTag.getQualifiedName() + "\" Start Tag"));
                popup.add(new WrapperAction(parent.getGotoEndTagAction(),
                        "Goto \"" + parentTag.getQualifiedName() + "\" End Tag"));
                popup.addSeparator();
                popup.add(new WrapperAction(parent.getSplitElementAction(),
                        "Split \"" + parentTag.getQualifiedName() + "\" Element"));
                popup.addSeparator();
                popup.add(new WrapperAction(parent.getSelectElementAction(),
                        "Select \"" + parentTag.getQualifiedName() + "\" Element"));
                popup.add(new WrapperAction(parent.getSelectElementContentAction(),
                        "Select \"" + parentTag.getQualifiedName() + "\" Element Content"));
                popup.addSeparator();
            }
            popup.add(parent.getParseAction());
            popup.add(parent.getValidateAction());
            popup.addSeparator();
            popup.add(parent.getPasteAction());
            popup.addSeparator();
            popup.add(parent.getSaveAction());
            popup.add(parent.getSaveAsAction());
            popup.addSeparator();
            popup.add(parent.getCloseAction());
        }
        GUIUtilities.alignMenu(popup);
        popup.show(getEditor(), e.getX(), e.getY());
    }

    /**
     * Tags the selected text or if the caret is in a tag, 
     * creates the tag after the current tag.
     *
     * @param name the name of the tag.
     */
    public void insertTag(String name) {

        // need the current tag specifically.
        Tag tag = getCurrentTag();
        if (tag != null) {
            if (tag.getType() == Tag.END_TAG) {
                getEditor().setCaretPosition(tag.getStart());
                tagSelectedText(name);
            } else if (tag.getType() == Tag.EMPTY_TAG) {
                view.getChangeManager().startCompound(true);
                getEditor().select(tag.getEnd() - 2, tag.getEnd());
                StringBuffer buffer = new StringBuffer("><");
                buffer.append(name);
                buffer.append(">");
                buffer.append("</");
                buffer.append(name);
                buffer.append(">");
                buffer.append("</");
                buffer.append(tag.getQualifiedName());
                buffer.append(">");
                getEditor().replaceSelection(buffer.toString());
                getEditor().setCaretPosition(tag.getEnd() + name.length() + 1);
                view.getChangeManager().endCompound();
            } else { // all other tags, place the element after the tag.
                getEditor().setCaretPosition(tag.getEnd());
                tagSelectedText(name);
            }
        } else {
            tagSelectedText(name);
        }
    }

    //   public void gotoCursor() {
    //      try{
    //         Rectangle pos = getEditor().modelToView( getEditor().getCaretPosition());
    //         getEditor().scrollRectToVisible( pos);
    //      } catch ( Exception e) {
    //         e.printStackTrace();
    //      }
    //   }
    /**
     * Tags the selected text.
     *
     * @param name the name of the tag.
     */
    public void tagSelectedText(String name) {

        view.getChangeManager().startCompound(true);
        String selection = getEditor().getSelectedText();
        StringBuffer buffer = new StringBuffer("<");
        buffer.append(name);
        buffer.append(">");
        if (selection != null) {
            buffer.append(selection);
        }
        buffer.append("</");
        buffer.append(name);
        buffer.append(">");
        getEditor().replaceSelection(buffer.toString());
        if (selection == null || selection.length() == 0) {
            getEditor().setCaretPosition(getEditor().getCaretPosition() - (name.length() + 3));
        }
        view.getChangeManager().endCompound();
    }

    /**
     * Gets the selected editor panel
     * @return selectedEditor
     */
    public EditorPanel getSelectedEditorPanel() {

        return (this.selectedEditor);
    }

    /**
     * Appends an attribute to the current tag...
     *
     * @param name the full name of the attribute.
     */
    public void appendAttribute(String name) {

        view.getChangeManager().startCompound(true);
        Tag startTag = getCurrentStartTag();
        if (startTag != null) {
            if (startTag.getType() == Tag.START_TAG) {
                getEditor().setCaretPosition(startTag.getEnd() - 1);
            } else { // EMPTY_TAG
                getEditor().setCaretPosition(startTag.getEnd() - 2);
            }
            StringBuffer buffer = new StringBuffer(" ");
            buffer.append(name);
            buffer.append("=\"\"");
            getEditor().replaceSelection(buffer.toString());
            getEditor().setCaretPosition(getEditor().getCaretPosition() - 1);
        }
        view.getChangeManager().endCompound();
    }

    /**
     * Selects the attrubte value of the current tag...
     *
     * @param name the full name of the attribute.
     * @param value the value of the attribute.
     */
    public void selectAttributeValue(String name, String value) {

        Tag startTag = getCurrentStartTag();
        if (startTag != null) {
            int start = startTag.getStart();
            int offset = startTag.getAttributeValueOffset(name);
            getEditor().select(start + offset, start + offset + value.length());
        }
    }

    /**
     * Comments the selected text.
     */
    public void lock() {

        if (getEditor().getLocked() == XmlEditorPane.NOT_LOCKED) {
            topEditor.getEditor().setLocked(XmlEditorPane.LOCKED);
            bottomEditor.getEditor().setLocked(XmlEditorPane.LOCKED);
        } else if (getEditor().getLocked() == XmlEditorPane.LOCKED) {
            topEditor.getEditor().setLocked(XmlEditorPane.DOUBLE_LOCKED);
            bottomEditor.getEditor().setLocked(XmlEditorPane.DOUBLE_LOCKED);
        } else {
            topEditor.getEditor().setLocked(XmlEditorPane.NOT_LOCKED);
            bottomEditor.getEditor().setLocked(XmlEditorPane.NOT_LOCKED);
        }
        updateHelper();
    }

    /**
     * Comments the selected text.
     */
    public void commentSelectedText() {

        view.getChangeManager().startCompound(true);
        try {
            XmlDocument doc = (XmlDocument) getEditor().getDocument();
            int pos = getEditor().getCaretPosition();
            if (doc.isComment(pos)) {
                String text = doc.getText(0, doc.getLength());
                int start = text.lastIndexOf("<!--", pos);
                if (start != -1) {
                    int end = text.indexOf("-->", start);
                    doc.remove(end, 3);
                    doc.remove(start, 4);
                }
            } else {
                String selection = getEditor().getSelectedText();
                StringBuffer buffer = new StringBuffer("<!--");
                if (selection != null) {
                    buffer.append(selection);
                }
                buffer.append("-->");
                getEditor().replaceSelection(buffer.toString());
                if (selection == null) {
                    getEditor().setCaretPosition(getEditor().getCaretPosition() - 3);
                }
            }
        } catch (Exception e) {
        } finally {
            view.getChangeManager().endCompound();
        }
    }

    private FragmentDialog getFragmentDialog() {

        if (fragmentDialog == null) {
            fragmentDialog = new FragmentDialog(parent);
        }
        return fragmentDialog;
    }

    public void insertFragment(boolean block, String content) {

        if (DEBUG)
            System.out.println("Editor.insertFragment( " + block + ", " + content + ")");
        view.getChangeManager().startCompound(true);
        StringBuffer buffer = null;
        if (block) {
            content = "\n" + content;
        }
        try {
            XmlDocument doc = (XmlDocument) getEditor().getDocument();
            int pos = getEditor().getCaretPosition();
            int selectionStart = getEditor().getSelectionStart();
            String selection = getEditor().getSelectedText();
            if (selection == null) {
                selection = "";
            }
            Tag tag = getCurrentStartTag();
            StringBuffer whitespace = new StringBuffer();
            if (tag != null) {
                int index = doc.getDefaultRootElement().getElementIndex(tag.getStart());
                Element element = doc.getDefaultRootElement().getElement(index);
                int start = element.getStartOffset();
                int end = element.getEndOffset();
                String line = doc.getText(start, end - start);
                whitespace = whitespace.append(TextPreferences.getTabString());
                for (int i = 0; (i < line.length()); i++) {
                    char ch = line.charAt(i);
                    if (((ch != '\n') && (ch != '\f') && (ch != '\r')) && Character.isWhitespace(ch)) {
                        whitespace.append(ch);
                    } else {
                        break;
                    }
                }
            }
            Vector keys = getFragmentKeys(content);
            if (keys.size() > 0) {
                FragmentDialog dialog = getFragmentDialog();
                dialog.show(keys);
                if (!dialog.isCancelled()) {
                    for (int i = 0; i < keys.size(); i++) {
                        String name = (String) keys.elementAt(i);
                        String value = dialog.getValue(name);
                        content = StringUtilities.replace(content, "${" + name + "}", value);
                    }
                } else {
                    return;
                }
            }
            content = StringUtilities.replace(content, "${selection}", selection);
            content = StringUtilities.replace(content, "\n", "\n" + whitespace);
            int cursorStart = content.indexOf("${cursor}");
            // add everything before the cursor start.
            if (cursorStart != -1) {
                buffer = new StringBuffer(content.substring(0, cursorStart));
                buffer.append(content.substring(cursorStart + 9));
            } else {
                buffer = new StringBuffer(content);
            }
            if (block) {
                buffer.append("\n");
            }
            content = buffer.toString();
            getEditor().replaceSelection(content);
            if (cursorStart == -1) {
                cursorStart = content.length();
            }
            if (selection == null) {
                getEditor().setCaretPosition(pos + cursorStart);
            } else {
                getEditor().setCaretPosition(selectionStart + cursorStart);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            view.getChangeManager().endCompound();
        }
    }

    private Vector getFragmentKeys(String content) {

        Vector keys = new Vector();
        int start = content.indexOf("${");
        while (start != -1) {
            int end = content.indexOf('}', start);
            if (end != -1) {
                String key = content.substring(start + 2, end);
                if (!key.equals("cursor") && !key.equals("selection")) {
                    if (!keys.contains(key)) {
                        keys.add(key);
                    }
                }
            } else {
                break;
            }
            start = content.indexOf("${", end);
        }
        return keys;
    }

    public void selectElement() {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        //      int pos = getEditor().getCaretPosition();
        Tag tag = getCurrentTag();
        if (tag != null) {
            if (tag.getType() == Tag.START_TAG) {
                Tag endTag = doc.getEndTag(tag);
                if (endTag != null) {
                    getEditor().select(tag.getStart(), endTag.getEnd());
                } else {
                    System.err.println(
                            "WARNING: How strange, could not find an end-tag for: " + tag.getQualifiedName());
                }
            } else if (tag.getType() == Tag.END_TAG) {
                Tag startTag = doc.getStartTag(tag);
                if (startTag != null) {
                    getEditor().select(startTag.getStart(), tag.getEnd());
                } else {
                    System.err.println(
                            "WARNING: How strange, could not find a start-tag for: " + tag.getQualifiedName());
                }
            } else if (tag.getType() == Tag.EMPTY_TAG) {
                getEditor().select(tag.getStart(), tag.getEnd());
            } else {
                selectParentElement();
            }
        } else {
            selectParentElement();
        }
    }

    public void selectElementContent() {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        //      int pos = getEditor().getCaretPosition();
        Tag tag = getCurrentTag();
        if (tag != null) {
            if (tag.getType() == Tag.START_TAG) {
                Tag endTag = doc.getEndTag(tag);
                if (endTag != null) {
                    getEditor().select(tag.getEnd(), endTag.getStart());
                } else {
                    System.err.println(
                            "WARNING: How strange, could not find an end-tag for: " + tag.getQualifiedName());
                }
            } else if (tag.getType() == Tag.END_TAG) {
                Tag startTag = doc.getStartTag(tag);
                if (startTag != null) {
                    getEditor().select(startTag.getEnd(), tag.getStart());
                } else {
                    System.err.println(
                            "WARNING: How strange, could not find a start-tag for: " + tag.getQualifiedName());
                }
            } else {
                selectParentElementContent();
            }
        } else {
            selectParentElementContent();
        }
    }

    public void selectParentElement() {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        Tag startTag = getParentStartTag();
        if (startTag != null) {
            Tag endTag = doc.getEndTag(startTag);
            if (endTag != null) {
                getEditor().select(startTag.getStart(), endTag.getEnd());
            } else {
                System.err.println(
                        "WARNING: How strange, could not find an end-tag for: " + startTag.getQualifiedName());
            }
        }
    }

    public void gotoEndTag() {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        Tag tag = getCurrentTag();
        if (tag != null) {
            if (tag.getType() == Tag.START_TAG) {
                Tag endTag = doc.getEndTag(tag);
                if (endTag != null) {
                    getEditor().setCaretPosition(endTag.getEnd());
                    getEditor().moveCaretPosition(endTag.getStart());
                    //               editor.select( endTag.getStart(), endTag.getEnd());
                }
            } else if (tag.getType() == Tag.END_TAG) {
                getEditor().setCaretPosition(tag.getEnd());
                getEditor().moveCaretPosition(tag.getStart());
                //            editor.select( tag.getStart(), tag.getEnd());
            } else {
                Tag startTag = getParentStartTag();
                if (startTag != null) {
                    Tag endTag = doc.getEndTag(startTag);
                    if (endTag != null) {
                        getEditor().setCaretPosition(endTag.getEnd());
                        getEditor().moveCaretPosition(endTag.getStart());
                        //                  editor.select( endTag.getStart(), endTag.getEnd());
                    }
                }
            }
        } else {
            Tag startTag = getParentStartTag();
            if (startTag != null) {
                Tag endTag = doc.getEndTag(startTag);
                if (endTag != null) {
                    //               editor.select( endTag.getStart(), endTag.getEnd());
                    getEditor().setCaretPosition(endTag.getEnd());
                    getEditor().moveCaretPosition(endTag.getStart());
                }
            }
        }
    }

    public void gotoStartTag() {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        Tag tag = getCurrentTag();
        if (tag != null) {
            if (tag.getType() == Tag.START_TAG) {
                getEditor().select(tag.getStart(), tag.getEnd());
            } else if (tag.getType() == Tag.END_TAG) {
                Tag startTag = doc.getStartTag(tag);
                if (startTag != null) {
                    getEditor().select(startTag.getStart(), startTag.getEnd());
                }
            } else {
                Tag startTag = getParentStartTag();
                if (startTag != null) {
                    getEditor().select(startTag.getStart(), startTag.getEnd());
                }
            }
        } else {
            Tag startTag = getParentStartTag();
            if (startTag != null) {
                getEditor().select(startTag.getStart(), startTag.getEnd());
            }
        }
    }

    public void toggleEmptyElement() {

        Tag tag = getCurrentTag();
        if (tag != null && tag.getType() == Tag.EMPTY_TAG) {
            view.getChangeManager().startCompound(true);
            getEditor().select(tag.getEnd() - 2, tag.getEnd());
            StringBuffer buffer = new StringBuffer(">");
            buffer.append("</");
            buffer.append(tag.getQualifiedName());
            buffer.append(">");
            getEditor().replaceSelection(buffer.toString());
            getEditor().setCaretPosition(tag.getEnd() - 1);
            view.getChangeManager().endCompound();
        }
    }

    public void renameCurrentElement(String name) {

        int pos = getCursorPosition();
        Tag endTag = null;
        Tag startTag = getCurrentTag();
        if (startTag != null && startTag.getType() == Tag.END_TAG) {
            endTag = startTag;
            startTag = ((XmlDocument) getEditor().getDocument()).getStartTag(startTag);
        } else if (startTag == null
                || (startTag.getType() != Tag.START_TAG && startTag.getType() != Tag.EMPTY_TAG)) {
            startTag = getParentStartTag();
        }
        if (startTag != null) {
            if (startTag.getType() == Tag.EMPTY_TAG) {
                view.getChangeManager().startCompound(true);
                // same start and end-tag ...
                getEditor().select(startTag.getStart() + 1,
                        startTag.getStart() + 1 + startTag.getQualifiedName().length());
                getEditor().replaceSelection(name);
                view.getChangeManager().endCompound();
            } else {
                if (endTag == null) {
                    endTag = ((XmlDocument) getEditor().getDocument()).getEndTag(startTag);
                }
                if (endTag != null && endTag.getQualifiedName().equals(startTag.getQualifiedName())) {
                    view.getChangeManager().startCompound(true);
                    // same start and end-tag ...
                    getEditor().select(endTag.getStart() + 2,
                            endTag.getStart() + 2 + endTag.getQualifiedName().length());
                    getEditor().replaceSelection(name);
                    getEditor().select(startTag.getStart() + 1,
                            startTag.getStart() + 1 + startTag.getQualifiedName().length());
                    getEditor().replaceSelection(name);
                    view.getChangeManager().endCompound();
                }
            }
        }
    }

    public void gotoNextAttributeValue() {

        int pos = getCursorPosition();
        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        Tag tag = getCurrentTag();
        if (tag == null) {
            tag = doc.getNextTag(pos);
        }
        int counter = 0; // time out counter
        while (tag != null && counter < 1000) {
            if (tag.getType() == Tag.START_TAG || tag.getType() == Tag.EMPTY_TAG) {
                Vector names = tag.getAttributeNames();
                if (names != null) {
                    int attributePos = -1;
                    for (int i = 0; i < names.size(); i++) {
                        String name = (String) names.elementAt(i);
                        int offset = tag.getAttributeValueOffset(name) + tag.getStart();
                        if (offset > pos && (attributePos == -1 || attributePos > offset)) {
                            attributePos = offset;
                        }
                    }
                    if (attributePos != -1) {
                        getEditor().setCaretPosition(attributePos);
                        return;
                    }
                }
            }
            if (tag.getEnd() < (doc.getLength() - 1)) {
                tag = doc.getNextTag(tag.getEnd());
            } else {
                tag = null;
            }
            counter++;
        }
    }

    public void gotoPreviousAttributeValue() {

        int pos = getCursorPosition();
        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        Tag tag = getCurrentTag();
        if (tag == null) {
            tag = doc.getPreviousTag(pos);
        }
        int counter = 0; // time out counter
        while (tag != null && counter < 1000) {
            if (tag.getType() == Tag.START_TAG || tag.getType() == Tag.EMPTY_TAG) {
                Vector names = tag.getAttributeNames();
                if (names != null) {
                    int attributePos = -1;
                    for (int i = 0; i < names.size(); i++) {
                        String name = (String) names.elementAt(i);
                        int offset = tag.getAttributeValueOffset(name) + tag.getStart();
                        if (offset < pos && attributePos < offset) {
                            attributePos = offset;
                        }
                    }
                    if (attributePos != -1) {
                        getEditor().setCaretPosition(attributePos);
                        return;
                    }
                }
            }
            tag = doc.getPreviousTag(tag.getStart());
            counter++;
        }
    }

    public void selectParentElementContent() {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        Tag startTag = getParentStartTag();
        if (startTag != null) {
            Tag endTag = doc.getEndTag(startTag);
            if (endTag != null) {
                getEditor().select(startTag.getEnd(), endTag.getStart());
            } else {
                System.err.println(
                        "WARNING: How strange, could not find an end-tag for: " + startTag.getQualifiedName());
            }
        }
    }

    /**
     * CDATAs the selected text.
     */
    public void cdataSelectedText() {

        view.getChangeManager().startCompound(true);
        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        int pos = getEditor().getCaretPosition();
        try {
            if (doc.isCDATA(pos)) {
                String text = doc.getText(0, doc.getLength());
                int start = text.lastIndexOf("<![CDATA[", pos);
                int end = text.indexOf("]]>", pos);
                getEditor().select(start, end + 3);
                text = getEditor().getSelectedText();
                text = text.substring(9, text.length() - 3);
                text = substituteCDATACharacters(text);
                getEditor().replaceSelection(text);
            } else {
                String selection = getEditor().getSelectedText();
                StringBuffer buffer = new StringBuffer("<![CDATA[");
                if (selection != null) {
                    buffer.append(selection);
                }
                buffer.append("]]>");
                getEditor().replaceSelection(buffer.toString());
                if (selection == null) {
                    getEditor().setCaretPosition(getEditor().getCaretPosition() - 3);
                }
            }
        } catch (Exception e) {
        } finally {
            view.getChangeManager().endCompound();
        }
    }

    /**
     * Unindents the selected text.
     */
    public void unindentSelectedText() {

        view.getChangeManager().startCompound(true);
        int start = Math.min(getEditor().getSelectionStart(), getEditor().getSelectionEnd());
        int end = Math.max(getEditor().getSelectionStart(), getEditor().getSelectionEnd());
        XmlDocument document = (XmlDocument) getEditor().getDocument();
        Element root = document.getDefaultRootElement();
        int startElementIndex = root.getElementIndex(start);
        int endElementIndex = root.getElementIndex(end > start ? end - 1 : end);
        try {
            for (int i = startElementIndex; i < endElementIndex + 1; i++) {
                Element element = root.getElement(i);
                int off = element.getStartOffset();
                try {
                    String text = getEditor().getText(off, getEditor().getTabSize());
                    int spaces = 0;
                    int tab = -1;
                    while (spaces < getEditor().getTabSize()) {
                        if (text.charAt(spaces) == '\t') {
                            tab = off + spaces;
                            break;
                        } else if (text.charAt(spaces) != ' ') {
                            break;
                        }
                        spaces++;
                    }
                    if (tab != -1) {
                        document.remove(tab, 1);
                    } else if (spaces > 0) {
                        document.remove(off, spaces);
                    }
                } catch (Exception e) {
                }
            }
        } finally {
            view.getChangeManager().endCompound();
        }
    }

    /**
     * Substitutes the selected characters with entities.
     */
    public void substituteSelectedCharacters() {

        String text = getEditor().getSelectedText();
        if (text != null) {
            try {
                view.getChangeManager().startCompound(true);
                StringBuffer newText = new StringBuffer();
                for (int i = 0; i < text.length(); i++) {
                    char character = text.charAt(i);
                    if ((character == '<') && properties.isConvertLtToEntity()) {
                        newText.append("&lt;");
                    } else if (character == '>' && properties.isConvertGtToEntity()) {
                        newText.append("&gt;");
                    } else if (character == '&' && properties.isConvertAmpToEntity()) {
                        newText.append("&amp;");
                    } else if (character == '\'' && properties.isConvertAposToEntity()) {
                        newText.append("&apos;");
                    } else if (character == '\"' && properties.isConvertQuotToEntity()) {
                        newText.append("&quot;");
                    } else if (properties.isConvertCharacterToNamedEntity()
                            && (CommonEntities.getEntityName(character) != null) && character > 127) {
                        String name = CommonEntities.getEntityName(character);
                        if (!name.equals("lt") && !name.equals("gt") && !name.equals("amp") && !name.equals("apos")
                                && !name.equals("quot")) {
                            newText.append("&");
                            newText.append(name);
                            newText.append(";");
                        }
                    } else if (properties.isEscapeUnicodeCharacters()
                            && character >= properties.getUnicodeStartEntry()) {
                        newText.append("&#");
                        newText.append((int) character);
                        newText.append(";");
                    } else {
                        newText.append((char) character);
                    }
                }
                getEditor().replaceSelection(newText.toString());
            } finally {
                view.getChangeManager().endCompound();
            }
        }
    }

    private String substituteCDATACharacters(String text) {

        if (text != null) {
            StringBuffer newText = new StringBuffer();
            for (int i = 0; i < text.length(); i++) {
                char character = text.charAt(i);
                if ((character == '<')) {
                    newText.append("&lt;");
                } else if (character == '&') {
                    if (text.length() < i + 5 || !(text.charAt(i + 1) == 'a' && text.charAt(i + 2) == 'm'
                            && text.charAt(i + 3) == 'p' && text.charAt(i + 4) == ';')) {
                        newText.append("&amp;");
                    } else {
                        newText.append((char) character);
                    }
                } else {
                    newText.append((char) character);
                }
            }
            return newText.toString();
        }
        return null;
    }

    /**
     * Substitutes the selected entities with characters.
     */
    public void substituteSelectedEntities() {

        String text = getEditor().getSelectedText();
        if (text != null) {
            try {
                view.getChangeManager().startCompound(true);
                StringBuffer newText = new StringBuffer();
                for (int i = 0; i < text.length(); i++) {
                    char character = text.charAt(i);
                    if (character == '&') {
                        int entityStart = i;
                        int entityEnd = text.indexOf(';', entityStart) + 1;
                        if (entityEnd != 0) {
                            String entity = text.substring(entityStart, entityEnd);
                            //                     System.out.println( "Entity:"+entity);
                            if (entity.startsWith("&#")) {
                                if (properties.isConvertCharacterEntity()) {
                                    char newCharacter = CommonEntities.convertCharacterEntity(entity);
                                    if (newCharacter != -1) {
                                        newText.append((char) newCharacter);
                                        i += entity.length() - 1;
                                    } else {
                                        newText.append((char) character);
                                    }
                                } else {
                                    newText.append((char) character);
                                }
                            } else if (entity.equals("&lt;")) {
                                if (properties.isConvertLtToCharacter()) {
                                    newText.append("<");
                                    i += entity.length() - 1;
                                } else {
                                    newText.append((char) character);
                                }
                            } else if (entity.equals("&gt;")) {
                                if (properties.isConvertGtToCharacter()) {
                                    newText.append(">");
                                    i += entity.length() - 1;
                                } else {
                                    newText.append((char) character);
                                }
                            } else if (entity.equals("&apos;")) {
                                if (properties.isConvertAposToCharacter()) {
                                    newText.append("'");
                                    i += entity.length() - 1;
                                } else {
                                    newText.append((char) character);
                                }
                            } else if (entity.equals("&amp;")) {
                                if (properties.isConvertAmpToCharacter()) {
                                    newText.append("&");
                                    i += entity.length() - 1;
                                } else {
                                    newText.append((char) character);
                                }
                            } else if (entity.equals("&quot;")) {
                                if (properties.isConvertQuotToCharacter()) {
                                    newText.append("\"");
                                    i += entity.length() - 1;
                                } else {
                                    newText.append((char) character);
                                }
                            } else {
                                if (properties.isConvertNamedEntityToCharacter()) {
                                    char newCharacter = CommonEntities
                                            .getChar(entity.substring(1, entity.length() - 1));
                                    if (newCharacter != -1) {
                                        newText.append((char) newCharacter);
                                        i += entity.length() - 1;
                                    } else {
                                        newText.append((char) character);
                                    }
                                } else {
                                    newText.append((char) character);
                                }
                            }
                        } else {
                            newText.append((char) character);
                        }
                    } else {
                        newText.append((char) character);
                    }
                }
                getEditor().replaceSelection(newText.toString());
            } finally {
                view.getChangeManager().endCompound();
            }
        }
    }

    public void splitElement() {

        Tag tag = getParentStartTag();
        if (tag != null) {
            String qname = tag.getQualifiedName();
            StringBuffer buffer = new StringBuffer("</");
            buffer.append(qname);
            buffer.append("><");
            buffer.append(qname);
            buffer.append(">");
            getEditor().replaceSelection(buffer.toString());
        }
    }

    /**
     * Substitutes the selected entities with characters.
     */
    public void stripSelectedTags() {

        String text = getEditor().getSelectedText();
        if (text != null) {
            try {
                view.getChangeManager().startCompound(true);
                StringBuffer newText = new StringBuffer();
                for (int i = 0; i < text.length(); i++) {
                    char character = text.charAt(i);
                    if (character == '<') {
                        int tagStart = i;
                        int tagEnd = text.indexOf('>', tagStart) + 1;
                        if (tagEnd != 0) {
                            String tag = text.substring(tagStart, tagEnd);
                            if (tag.startsWith("<![CDATA[")) {
                                int cdataStart = tagStart;
                                int cdataEnd = text.indexOf("]]>", tagStart) + 3;
                                if (cdataEnd != 2) {
                                    String cdata = text.substring(cdataStart, cdataEnd);
                                    newText.append(cdata);
                                    i += cdata.length() - 1;
                                } else {
                                    newText.append(text.substring(cdataStart, text.length()));
                                    i = text.length();
                                }
                            } else if (tag.startsWith("<!--")) {
                                int commentStart = tagStart;
                                int commentEnd = text.indexOf("-->", commentStart) + 3;
                                if (commentEnd != 2) {
                                    String comment = text.substring(commentStart, commentEnd);
                                    newText.append(comment);
                                    i += comment.length() - 1;
                                } else {
                                    newText.append(text.substring(commentStart, text.length()));
                                    i = text.length();
                                }
                            } else { // it must be a tag, don't include it...
                                i += tag.length() - 1;
                                if (((tagStart - 1) >= 0) && ((i + 1) <= (text.length() - 1))
                                        && !Character.isWhitespace(text.charAt(tagStart - 1))
                                        && !Character.isWhitespace(text.charAt(i + 1))) {
                                    newText.append(" ");
                                }
                            }
                        } else {
                            newText.append(text.substring(tagStart, text.length()));
                            i = text.length();
                        }
                    } else {
                        newText.append((char) character);
                    }
                }
                getEditor().replaceSelection(newText.toString());
            } finally {
                view.getChangeManager().endCompound();
            }
        }
    }

    public String getSelectedText() {

        return getEditor().getSelectedText();
    }

    /**
     * Returns either the currently selected text, or the 
     * current string where the caret is postioned.
     *
     * @return the current selected text.
     */
    public String getCurrentText() {

        String value = getEditor().getSelectedText();
        if (value == null) {
            try {
                int pos = getEditor().getCaretPosition();
                XmlDocument document = (XmlDocument) getEditor().getDocument();
                Element root = document.getDefaultRootElement();
                Element element = root.getElement(root.getElementIndex(pos));
                int start = element.getStartOffset();
                int end = element.getEndOffset();
                String line = document.getText(start, end - start);
                start = pos - start;
                end = start;
                while (Character.isLetterOrDigit(line.charAt(start)) && start >= 0) {
                    start--;
                }
                while (Character.isLetterOrDigit(line.charAt(end)) && end < line.length()) {
                    end++;
                }
                if (start + 1 < end) {
                    value = line.substring(start + 1, end);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (value.indexOf('\n') != -1) {
            value = value.substring(0, value.indexOf('\n'));
        }
        return value;
    }

    public URL getCurrentURL() {

        String value = getEditor().getSelectedText();
        if (value == null) {
            try {
                int pos = getEditor().getCaretPosition();
                XmlDocument document = (XmlDocument) getEditor().getDocument();
                Element root = document.getDefaultRootElement();
                Element element = root.getElement(root.getElementIndex(pos));
                int start = element.getStartOffset();
                int end = element.getEndOffset();
                String line = document.getText(start, end - start);
                start = pos - start;
                end = start;
                while (URLUtilities.isURLCharacter(line.charAt(start)) && start >= 0) {
                    start--;
                }
                while (URLUtilities.isURLCharacter(line.charAt(end)) && end < line.length()) {
                    end++;
                }
                if (start + 1 < end) {
                    value = line.substring(start + 1, end);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return URLUtilities.toURL(URLUtilities.resolveURL(document.getURL(), value));
    }

    /**
     * Indents the selected text.
     *
     * @param tab when true the tab key is used as indentation.
     */
    public void indentSelectedText(boolean tab) {

        view.getChangeManager().startCompound(true);
        int start = Math.min(getEditor().getSelectionStart(), getEditor().getSelectionEnd());
        int end = Math.max(getEditor().getSelectionStart(), getEditor().getSelectionEnd());
        try {
            if (tab) {
                if (start != end) {
                    XmlDocument document = (XmlDocument) getEditor().getDocument();
                    Element root = document.getDefaultRootElement();
                    int startElementIndex = root.getElementIndex(start);
                    int endElementIndex = root.getElementIndex(end);
                    if (startElementIndex != endElementIndex) {
                        endElementIndex = root.getElementIndex(end - 1);
                        for (int i = startElementIndex; i < endElementIndex + 1; i++) {
                            Element element = root.getElement(i);
                            int off = element.getStartOffset();
                            try {
                                document.insertString(element.getStartOffset(), getTabString(), null);
                            } catch (Exception e) {
                            }
                        }
                    } else {
                        getEditor().replaceSelection(getTabString());
                    }
                } else {
                    getEditor().replaceSelection(getTabString());
                }
            } else {
                XmlDocument document = (XmlDocument) getEditor().getDocument();
                Element root = document.getDefaultRootElement();
                int startElementIndex = root.getElementIndex(start);
                int endElementIndex = root.getElementIndex(end > start ? end - 1 : end);
                for (int i = startElementIndex; i < endElementIndex + 1; i++) {
                    Element element = root.getElement(i);
                    int off = element.getStartOffset();
                    try {
                        document.insertString(element.getStartOffset(), getTabString(), null);
                    } catch (Exception e) {
                    }
                }
            }
        } finally {
            view.getChangeManager().endCompound();
        }
    }

    /**
     * Returns the editor properties.
     *
     * @return the editor properties.
     */
    public EditorProperties getProperties() {

        return properties;
    }

    /**
     * returns the string representation of the tab character.
     *
     * @return the String the tab should be replaced with.
     */
    public String getTabString() {

        return TextPreferences.getTabString();
    }

    /**
     * Get the cursor position.
     *
     * @return the current position of the cursor.
     */
    public int getCursorPosition() {

        return getEditor().getCaretPosition();
    }

    /**
     * Sets the position of the cursor.
     *
     * @param pos the new cursor position.
     */
    public void setCursorPosition(int pos) {

        int length = getEditor().getDocument().getLength();
        if (pos < 0) {
            pos = 0;
        } else if (pos >= length && length > 0) {
            pos = length - 1;
        }
        getEditor().setCaretPosition(pos);
    }

    /**
     * Formats the text to a nice DOM4J format.
     */
    /*   public void format() throws SAXParseException, IOException {
     view.getChangeManager().startCompound( true);
        
     try {
     LicenseManager licenseManager = LicenseManager.getInstance();
     licenseManager.isValid( com.cladonia.license.KeyGenerator.generate(7), "Exchanger XML Editor");
     } catch (Exception x) {
     System.exit(0);
     return;
     }
        
     try {
     String text = editor.getText( 0, editor.getDocument().getLength());
     ByteArrayInputStream stream = new ByteArrayInputStream( text.getBytes( document.getJavaEncoding()));
     InputStreamReader reader = new InputStreamReader( stream, document.getJavaEncoding());
     URL url = document.getURL();
     String systemId = null;
        
     if ( url != null) {
     systemId = url.toString();
     }
         
     SAXReader sax = XMLUtilities.createReader( false);
     sax.setStripWhitespaceText( false);
     sax.setMergeAdjacentText( false);
        
     XDocument doc = XMLUtilities.parse( sax, new BufferedReader( reader), systemId);
        
     int pos = editor.getCaretPosition();
         
     ByteArrayOutputStream out = new ByteArrayOutputStream();
        
     OutputFormat format = new OutputFormat();
     format.setEncoding( doc.getEncoding());
         
     XMLFormatter formatter = new XMLFormatter( out, format);
         
     //         EditorProperties properties = config.getEditorProperties();
     switch ( properties.getFormatType()) {
     case EditorProperties.FORMAT_CUSTOM:
     if ( properties.isCustomIndent()) {
     format.setIndent( getTabString());
     } else {
     * format.setIndent( ""); }
     * 
     * format.setNewlines( properties.isCustomNewline()); format.setPadText(
     * properties.isCustomPadText());
     * 
     * if ( properties.isWrapText()) { formatter.setMaxLineLength(
     * properties.getWrappingColumn()); }
     *  // formatter.setIndentSize( TextPreferences.getTabSize());
     * formatter.setTrimText( properties.isCustomStrip());
     * formatter.setPreserveMixedContent(
     * properties.isCustomPreserveMixedContent()); break; case
     * EditorProperties.FORMAT_COMPACT: if ( properties.isWrapText()) {
     * formatter.setMaxLineLength( properties.getWrappingColumn()); }
     *  // formatter.setIndentSize( TextPreferences.getTabSize());
     * 
     * format.setIndent( ""); format.setNewlines( false); format.setPadText(
     * false);
     * 
     * formatter.setTrimText( true); formatter.setPreserveMixedContent( false);
     * break; case EditorProperties.FORMAT_STANDARD: if (
     * properties.isWrapText()) { formatter.setMaxLineLength(
     * properties.getWrappingColumn()); } // formatter.setIndentSize(
     * TextPreferences.getTabSize());
     * 
     * format.setIndent( getTabString());
     * 
     * format.setNewlines( true); format.setPadText( false);
     * 
     * formatter.setTrimText( true); formatter.setPreserveMixedContent( true);
     * break; }
     * 
     * formatter.write( doc); String output = out.toString( doc.getEncoding()); //
     * System.out.println( output);
     * 
     * try { // use the normal XML plus writer... document.setText( output); }
     * catch ( SAXParseException e) { e.printStackTrace(); throw e; } catch (
     * final IOException e) { e.printStackTrace(); throw e; } catch ( Exception e) {
     * e.printStackTrace(); }
     * 
     * formatter.flush();
     * 
     * String result = document.getText();
     * 
     * editor.setText( result);
     * ((XmlDocument)editor.getDocument()).resetUpdates();
     *  // force another parse! // document.setText( result);
     * 
     * if ( result.length() < pos) { pos = result.length(); }
     * 
     * editor.setCaretPosition( pos);
     *  } catch( BadLocationException e) { e.printStackTrace(); } finally { //
     * enableParsing(); view.getChangeManager().endCompound(); } }
     */
    /**
     * Formats the text to a nice DOM4J format.
     */

    /*
     * public void canonicalize() throws Exception, SAXParseException,
     * IOException { view.getChangeManager().startCompound( true);
     * 
     * try { int pos = editor.getCaretPosition();
     * 
     * document.canonicalize(); String text = document.getText();
     * 
     * editor.setText( text);
     * ((XmlDocument)editor.getDocument()).resetUpdates();
     * 
     * if ( text.length() < pos) { pos = text.length(); }
     * 
     * editor.setCaretPosition( pos);
     *  } catch( BadLocationException e) { e.printStackTrace(); } finally {
     * view.getChangeManager().endCompound(); }
     */
    /**
     * Selects the indicated line.
     * 
     * @param line
     *            the line to select.
     */
    public void selectLine(int line) {

        getEditor().selectLine(line);
    }

    public void select(int line, int start, int end) {

        Element root = getEditor().getDocument().getDefaultRootElement();
        Element elem = root.getElement(line - 1);
        if (elem != null) {
            start = elem.getStartOffset() + start;
            end = elem.getStartOffset() + end;
            getEditor().select(start, end);
        }
    }

    /**
     * Selects the indicated line.
     * 
     * @param line
     *            the line to select.
     */
    public void selectLineForOffset(int off) {

        getEditor().selectLineForOffset(off);
    }

    /**
     * Selects the indicated line.
     * 
     * @param line
     *            the line to select.
     */
    public void selectLineWithoutEnd(int line) {

        if (line > 0) {
            Element root = getEditor().getDocument().getDefaultRootElement();
            Element elem = root.getElement(line - 1);
            if (elem != null) {
                int start = elem.getStartOffset();
                int end = elem.getEndOffset() - 1;
                getEditor().select(start, end);
            }
        }
    }

    /**
     * Gets the number of lines in the document.
     * 
     * @return the number of lines in the document.
     */
    public int getLines() {

        return getEditor().getLines();
    }

    /**
     * Gets the number of soft wrapped lines this line makes up.
     * 
     * @return the number of soft lines in the line.
     */
    public int getLineStart(int i) throws BadLocationException {

        return getEditor().getLineStart(i);
    }

    /**
     * Gets the number of soft wrapped lines this line makes up.
     * 
     * @return the number of soft lines in the line.
     */
    public int getLineNumber(int y) throws BadLocationException {

        return getEditor().getLineNumber(y);
    }

    public int getNextLineNumber(int i) throws BadLocationException {

        return getEditor().getNextLineNumber(i);
    }

    public ExchangerDocument getDocument() {

        return document;
    }

    /**
     * Inserts the name, selected in the selection dialog.
     */
    public void insertCurrentSelectedName() {

        view.getChangeManager().startCompound(true);
        try {
            String name = selectionPopup.getSelectedName();
            String prefix = selectionPopup.getPrefix();
            int popupType = selectionPopup.getPopupType();
            boolean attributeCompletion = ((XmlDocument) getEditor().getDocument())
                    .getAttributeName(getEditor().getCaretPosition()) != null;
            XmlDocument document = (XmlDocument) getEditor().getDocument();
            if (popupType == NameSelectionPopup.POPUP_TYPE_ATTRIBUTE) {
                if (attributeCompletion && !name.endsWith(":") && !name.endsWith("\"")) {
                    getEditor().replaceSelection(name.substring(prefix.length(), name.length()) + "=\"\"");
                    getEditor().setCaretPosition(getEditor().getCaretPosition() - 1);
                    promptText();
                } else if (attributeCompletion) {
                    getEditor().replaceSelection(name.substring(prefix.length(), name.length()));
                    if (name.endsWith(":")) {
                        promptText();
                    }
                } else { // attribute value
                    getEditor().replaceSelection(name.substring(prefix.length(), name.length()));
                    char next = ((XmlDocument) getEditor().getDocument())
                            .getLastCharacter(getEditor().getCaretPosition() + 1);
                    if ((next == '"' || next == '\'') && !(this.document.isXSL() && name.startsWith("$"))) {
                        getEditor().setCaretPosition(getEditor().getCaretPosition() + 1);
                    }
                }
            } else {
                if (prefix.startsWith("/")) {
                    getEditor().replaceSelection(name.substring(prefix.length(), name.length()) + ">");
                } else if (name.equals("!--")) {
                    getEditor().replaceSelection(name.substring(prefix.length(), name.length()) + "-->");
                    getEditor().setCaretPosition(getEditor().getCaretPosition() - 3);
                } else if (name.equals("![CDATA[")) {
                    getEditor().replaceSelection(name.substring(prefix.length(), name.length()) + "]]>");
                    getEditor().setCaretPosition(getEditor().getCaretPosition() - 3);
                } else if (name.equals("&lt;") && (prefix == null || prefix.trim().length() == 0)) {
                    getEditor().select(getEditor().getCaretPosition() - 1, getEditor().getCaretPosition());
                    getEditor().replaceSelection("&lt;");
                } else if (popupType == NameSelectionPopup.POPUP_TYPE_ENTITY) {
                    if (name.equals(NameSelectionPopup.SWAP_ENTITY_STRING)) {
                        selectionPopup.swap();
                        selectionPopup.setEntities(prefix);
                    } else if (name.equals(NameSelectionPopup.MORE_ENTITIES_STRING)) {
                        hideSelectionPopup();
                        getEditor().select(getEditor().getCaretPosition() - 1, getEditor().getCaretPosition());
                        parent.getInsertEntityAction().execute();
                    } else if (selectionPopup.isSwapped()) {
                        getEditor().select(getEditor().getCaretPosition() - prefix.length(),
                                getEditor().getCaretPosition());
                        getEditor().replaceSelection(name);
                    } else {
                        getEditor().select(getEditor().getCaretPosition() - prefix.length(),
                                getEditor().getCaretPosition());
                        getEditor().replaceSelection(name);
                    }
                } else if (name.startsWith("/")) {
                    getEditor().replaceSelection(name.substring(prefix.length(), name.length()) + ">");
                } else if (popupType == NameSelectionPopup.POPUP_TYPE_DECLARATION) {
                    if (name.equals("PUBLIC") || name.equals("SYSTEM")) {
                        getEditor().replaceSelection(name.substring(prefix.length(), name.length()) + " \"\"");
                        getEditor().setCaretPosition(getEditor().getCaretPosition() - 1);
                    } else {
                        getEditor().replaceSelection(name.substring(prefix.length(), name.length()));
                    }
                } else if (popupType == NameSelectionPopup.POPUP_TYPE_ELEMENT && name.endsWith(":")) {
                    getEditor().replaceSelection(name.substring(prefix.length(), name.length()));
                    promptText();
                } else {
                    getEditor().replaceSelection(name.substring(prefix.length(), name.length()));
                }
            }
            if (!name.equals(NameSelectionPopup.SWAP_ENTITY_STRING)
                    && !name.equals(NameSelectionPopup.MORE_ENTITIES_STRING)) {
                hideSelectionPopup();
            }
        } finally {
            view.getChangeManager().endCompound();
        }
    }

    /**
     * Inserts the name, selected in the selection dialog.
     */
    public void insert(String text) {

        getEditor().replaceSelection(text);
    }

    /**
     * Has the editor got the latest information in the document.
     * 
     * @return true when no document updates have been received after the
     *         latest text has been set.
     */
    public boolean hasLatestInformation() {

        return hasLatest;
    }

    public void setProperties() {

        //
    }

    public void setHighlight(boolean enabled) {

        topEditor.getEditor().setHighlight(enabled);
        bottomEditor.getEditor().setHighlight(enabled);
        this.revalidate();
        this.repaint();
    }

    public void setErrorHighlighting(boolean enabled) {

        topEditor.getEditor().setErrorHighlighting(enabled);
        bottomEditor.getEditor().setErrorHighlighting(enabled);
        this.revalidate();
        this.repaint();
    }

    public boolean isHighlight() {

        return getEditor().isHighlight();
    }

    // Implementation of the ExchangerDocumentListener interface...
    public void documentUpdated(ExchangerDocumentEvent event) {

        if (DEBUG)
            System.out.println("Editor.documentUpdated( " + event + ")");
        if (event.getType() == ExchangerDocumentEvent.CONTENT_UPDATED
                || event.getType() == ExchangerDocumentEvent.TEXT_UPDATED) {
            hasLatest = false;
        }
    }

    // Implementation of UndoableEditListener
    /**
     * Messaged when the Document has created an edit, the edit is added to
     * <code>undo</code>, an instance of UndoManager.
     */
    public void undoableEditHappened(UndoableEditEvent e) {

        if (DEBUG)
            System.out.println("Editor.undoableEditHappened( " + e.getSource() + ")");
        view.getChangeManager().addEdit(e.getEdit());
        if (!view.getChangeManager().isCompound()) {
            getEditor().repaint();
            if (insertHappened) {
                //             System.out.println( "caretUpdate()");
                //            examiner.setPosition( getEditor().getCaretPosition());
                promptText();
            }
        }
    }

    private Vector getCurrentAttributeValues() {

        if (getEditor() != null) {
            int off = getEditor().getCaretPosition();
            Tag tag = getCurrentTag();
            if (tag != null) {
                String attribute = tag.getAttributeName(off);
                return getAttributeValues(attribute);
            }
        }
        return null;
    }

    private Vector getCurrentAttributes() {

        if (selectedEditor != null) {
            Vector result = new Vector();
            SchemaDocument schema = null;
            Tag child = getCurrentTag();
            if (child != null && child.getType() == Tag.END_TAG) {
                child = ((XmlDocument) getEditor().getDocument()).getStartTag(child);
            } else if (child == null || (child.getType() != Tag.START_TAG && child.getType() != Tag.EMPTY_TAG)) {
                child = getParentStartTag();
            }
            Tag tag = getParentStartTag(child);
            while (tag != null) {
                ElementInformation element = getElement(tag, child);
                if (element != null) {
                    result.add(element.getAttributes());
                    break;
                }
                tag = getParentStartTag(tag);
            }
            // could not find tag...
            if (child != null && tag == null) {
                Vector elements = getAllElements();
                for (int i = 0; i < elements.size(); i++) {
                    ElementInformation model = (ElementInformation) elements.elementAt(i);
                    if (child.getQualifiedName().equals(model.getQualifiedName())) {
                        result.add(model.getAttributes());
                        break;
                    }
                }
            }
            result.add(getAnyAttributes());
            return result;
        }
        return null;
    }

    public ElementInformation getCurrentElement() {

        if (selectedEditor != null) {
            SchemaDocument schema = null;
            Tag tag = getCurrentTag();
            if (tag != null && tag.getType() == Tag.END_TAG) {
                tag = ((XmlDocument) getEditor().getDocument()).getStartTag(tag);
            } else if (tag == null || (tag.getType() != Tag.START_TAG && tag.getType() != Tag.EMPTY_TAG)) {
                tag = getParentStartTag();
            }
            if (schemas != null && schemas.size() > 0 && tag != null) {
                for (int i = 0; i < schemas.size() && schema == null; i++) {
                    Vector elements = ((SchemaDocument) schemas.elementAt(i)).getElements();
                    for (int j = 0; j < elements.size(); j++) {
                        if (((ElementInformation) elements.elementAt(j)).getQualifiedName()
                                .equals(tag.getQualifiedName())) {
                            schema = (SchemaDocument) schemas.elementAt(i);
                            break;
                        }
                    }
                }
            }
            if (schema != null) {
                while (tag != null) {
                    ElementInformation element = getElement(schema, tag);
                    if (element != null) {
                        return element;
                    }
                    tag = getParentStartTag(tag);
                }
            }
        }
        return null;
    }

    private Vector getCurrentChildElements() {

        if (selectedEditor != null) {
            Vector result = new Vector();
            SchemaDocument schema = null;
            Tag tag = getCurrentTag();
            if (tag != null && tag.getType() == Tag.END_TAG) {
                tag = ((XmlDocument) getEditor().getDocument()).getStartTag(tag);
            } else if (tag == null || (tag.getType() != Tag.START_TAG && tag.getType() != Tag.EMPTY_TAG)) {
                tag = getParentStartTag();
            }
            if (schemas != null && schemas.size() > 0 && tag != null) {
                for (int i = 0; i < schemas.size() && schema == null; i++) {
                    Vector elements = ((SchemaDocument) schemas.elementAt(i)).getElements();
                    for (int j = 0; j < elements.size(); j++) {
                        if (((ElementInformation) elements.elementAt(j)).getQualifiedName()
                                .equals(tag.getQualifiedName())) {
                            schema = (SchemaDocument) schemas.elementAt(i);
                            break;
                        }
                    }
                }
            }
            if (schema != null) {
                result.addElement(getChildElements(schema, tag));
            }
            if (schemas != null) {
                for (int i = 0; i < schemas.size(); i++) {
                    if (schemas.elementAt(i) != schema) {
                        result.addElement(getChildElements((SchemaDocument) schemas.elementAt(i), tag));
                    }
                }
            }
            return result;
        }
        return null;
    }

    private Vector getCurrentSiblings() {

        if (DEBUG)
            System.out.println("Editor.getCurrentSiblings()");
        if (selectedEditor != null) {
            Vector result = new Vector();
            SchemaDocument schema = null;
            Tag tag = getCurrentTag();
            if (tag != null && tag.getType() == Tag.END_TAG) {
                tag = ((XmlDocument) getEditor().getDocument()).getStartTag(tag);
            } else if (tag == null || (tag.getType() != Tag.START_TAG && tag.getType() != Tag.EMPTY_TAG)) {
                tag = getParentStartTag();
            }
            if (tag != null) {
                tag = ((XmlDocument) getEditor().getDocument()).getParentStartTag(tag.getStart());
                if (schemas != null && schemas.size() > 0 && tag != null) {
                    for (int i = 0; i < schemas.size() && schema == null; i++) {
                        Vector elements = ((SchemaDocument) schemas.elementAt(i)).getElements();
                        if (elements != null) {
                            for (int j = 0; j < elements.size(); j++) {
                                if (((ElementInformation) elements.elementAt(j)).getQualifiedName()
                                        .equals(tag.getQualifiedName())) {
                                    schema = (SchemaDocument) schemas.elementAt(i);
                                    break;
                                }
                            }
                        }
                    }
                }
                if (schema != null) {
                    result.addElement(getChildElements(schema, tag));
                }
            }
            if (schemas != null) {
                for (int i = 0; i < schemas.size(); i++) {
                    if (schemas.elementAt(i) != schema) {
                        result.addElement(getChildElements((SchemaDocument) schemas.elementAt(i), tag));
                    }
                }
            }
            return result;
        }
        return null;
    }

    protected void promptText() {

        if (properties.isTextPrompting()) {
            int off = getEditor().getCaretPosition();
            //         if ( ((XmlDocument)getEditor().getDocument()).isComment( off) ||
            // ((XmlDocument)getEditor().getDocument()).isCDATA( off)) {
            //            return;
            //         }
            if (document.isDTD()) {
                Tag tag = getCurrentTag();
                String value = ((XmlDocument) getEditor().getDocument()).getString(off);
                String name = null;
                if (tag != null) {
                    name = tag.getName();
                }
                if (value == null) {
                    value = "";
                }
                if (name != null) {
                    if (name.equals("ELEMENT")) {
                        showElementDeclarationSelectionPopup(tag, off, value);
                    } else if (name.equals("ATTLIST")) {
                        showAttlistDeclarationSelectionPopup(tag, off, value);
                    } else if (name.equals("ENTITY")) {
                        showEntityDeclarationSelectionPopup(tag, off, value);
                    } else if (name.equals("DOCTYPE")) {
                        showDoctypeDeclarationSelectionPopup(tag, off, value);
                    } else if (name.equals("NOTATION")) {
                        showNotationDeclarationSelectionPopup(tag, off, value);
                    } else if (value != null) {
                        if (tag.getType() == Tag.DECLARATION_TAG) {
                            showDeclarationSelectionPopup(getDeclarationNames(), "!" + name);
                        } else {
                            showDeclarationSelectionPopup(getDeclarationNames(), name);
                        }
                    }
                } else if (tag != null) {
                    showDeclarationSelectionPopup(getDeclarationNames(), value);
                }
            } else {
                char last = ((XmlDocument) getEditor().getDocument()).getLastCharacter(off);
                String attr = ((XmlDocument) getEditor().getDocument()).getAttributeName(off);
                String val = ((XmlDocument) getEditor().getDocument()).getAttributeValue(off);
                Tag parentTag = null;
                Tag tag = getCurrentTag();
                Tag doctypeTag = ((XmlDocument) getEditor().getDocument()).getDoctypeDeclarationTag();
                if (doctypeTag == null) {
                    parentTag = getParentStartTag();
                }
                boolean inDoctype = false;
                if (tag != null && doctypeTag == null && parentTag == null) {
                    String name = tag.getName();
                    if (tag.getName() == null || tag.getName().trim().length() == 0
                            || (tag.getName() != null && tag.getType() == Tag.DECLARATION_TAG)) {
                        inDoctype = true;
                    }
                } else if (tag != null && doctypeTag != null && doctypeTag.getEnd() >= tag.getStart()) {
                    inDoctype = true;
                }
                if (inDoctype) {
                    String value = ((XmlDocument) getEditor().getDocument()).getString(off);
                    String name = tag.getName();
                    if (value == null) {
                        value = "";
                    }
                    if (name != null) {
                        //                  System.out.println( "name = "+name);
                        if (name.equals("ELEMENT")) {
                            showElementDeclarationSelectionPopup(tag, off, value);
                        } else if (name.equals("ATTLIST")) {
                            showAttlistDeclarationSelectionPopup(tag, off, value);
                        } else if (name.equals("ENTITY")) {
                            showEntityDeclarationSelectionPopup(tag, off, value);
                        } else if (name.equals("DOCTYPE")) {
                            showDoctypeDeclarationSelectionPopup(tag, off, value);
                        } else if (name.equals("NOTATION")) {
                            showNotationDeclarationSelectionPopup(tag, off, value);
                        } else if (doctypeTag == null) {
                            Vector doctypeName = new Vector();
                            doctypeName.addElement("!DOCTYPE");
                            showDeclarationSelectionPopup(doctypeName, value);
                        } else {
                            if (tag.getType() == Tag.DECLARATION_TAG) {
                                showDeclarationSelectionPopup(getDeclarationNames(), "!" + name);
                            } else {
                                showDeclarationSelectionPopup(getDeclarationNames(), name);
                            }
                        }
                    } else {
                        if (doctypeTag == null) {
                            Vector doctypeName = new Vector();
                            doctypeName.addElement("!DOCTYPE");
                            showDeclarationSelectionPopup(doctypeName, value);
                        } else {
                            showDeclarationSelectionPopup(getDeclarationNames(), value);
                        }
                    }
                } else if (val != null && last != '\n' && last != '\r') {
                    if (tag != null && (tag.getType() == Tag.START_TAG || tag.getType() == Tag.EMPTY_TAG)) {
                        if (document.isXSL() && val != null) {
                            int index = val.lastIndexOf('$');
                            if (index != -1) {
                                val = val.substring(index);
                                examiner.getValues(getValuesPopupListener(val));
                            }
                        }
                        examiner.getValues(getValuesPopupListener(val));
                    }
                } else if (attr != null && last != '\n' && last != '\r') {
                    if (tag != null && (tag.getType() == Tag.START_TAG || tag.getType() == Tag.EMPTY_TAG)) {
                        examiner.getAttributes(getAttributesPopupListener(attr, tag));
                        //                  showAttributeSelectionPopup( attr, tag);
                    }
                } else {
                    String elem = ((XmlDocument) getEditor().getDocument()).getElementName(off);
                    if (elem != null) {
                        Tag currentTag = ((XmlDocument) getEditor().getDocument())
                                .getCurrentTag(off - (elem.length() + 1));
                        if (currentTag == null) {
                            String parent = ((XmlDocument) getEditor().getDocument()).getParentElementName(off);
                            String name = null;
                            if (tag != null) {
                                name = tag.getName();
                            }
                            if (elem.startsWith("/") && elem.length() == 1
                                    && (name == null || name.trim().length() == 0)) {
                                getEditor().replaceSelection(
                                        parent.substring(elem.length() - 1, parent.length()) + ">");
                            } else if (name == null || !name.equals(parent)) {
                                examiner.getElements(getElementsPopupListener(elem, parent));
                            }
                        } else if (elem.length() == 0) { // '<' in attribute
                                                         // value...
                            if (currentTag.getType() == Tag.DECLARATION_TAG) {
                                //                            System.out.println( "In Declaration Tag:
                                // "+currentTag);
                            } else {
                                showEntitySelectionPopup("<");
                            }
                        }
                    } else {
                        String entity = ((XmlDocument) getEditor().getDocument()).getEntityName(off);
                        Tag currentTag = ((XmlDocument) getEditor().getDocument()).getCurrentTag(off - 1);
                        if (entity != null) {
                            showEntitySelectionPopup(entity);
                        } else if (currentTag == null) { // the last character
                                                         // typed was in a
                                                         // Element Value
                            char lastChar = ((XmlDocument) getEditor().getDocument()).getLastCharacter(off);
                            if (lastChar != -1 && (lastChar == '\'' || lastChar == '"' || lastChar == '>')) {
                                showEntitySelectionPopup("" + lastChar);
                            }
                        } else if (currentTag.getType() == Tag.DECLARATION_TAG) { // were
                                                                                  // in
                                                                                  // an
                                                                                  // attribute
                                                                                  // value
                                                                                  // ...
                                                                                  //                        System.out.println( "In Declaration Tag:
                                                                                  // "+currentTag);
                        } else if (currentTag.getType() == Tag.START_TAG && currentTag.inAttributeValue(off)) { // were
                                                                                                                // in an
                                                                                                                // attribute
                                                                                                                // value
                                                                                                                // ...
                            char lastChar = ((XmlDocument) getEditor().getDocument()).getLastCharacter(off);
                            if (lastChar != -1 && (lastChar == '\'' || lastChar == '"' || lastChar == '>')) {
                                showEntitySelectionPopup("" + lastChar);
                            }
                        }
                    }
                }
            }
        }
    }

    // return the popup menu
    private JPopupMenu getPopupMenu() {

        if (popup == null) {
            popup = new JPopupMenu();
            popup.add(parent.getSelectElementAction());
            popup.add(parent.getSelectElementContentAction());
            popup.addSeparator();
            popup.add(parent.getParseAction());
            popup.add(parent.getValidateAction());
            popup.addSeparator();
            popup.add(parent.getDefaultScenarioAction());
            popup.add(parent.getSendSOAPAction());
            popup.addSeparator();
            popup.add(parent.getCutAction());
            popup.add(parent.getCopyAction());
            popup.add(parent.getPasteAction());
            popup.addSeparator();
            popup.add(parent.getUndoAction());
            popup.add(parent.getRedoAction());
            popup.addSeparator();
            popup.add(parent.getSaveAction());
            popup.add(parent.getSaveAsAction());
            popup.addSeparator();
            popup.add(parent.getCloseAction());
        }
        return popup;
    }

    public void setSchemas(Vector schemas) {

        this.schemas = schemas;
        allElements = null;
        globalElements = null;
    }

    public Vector getSchemas() {
        return (schemas);
    }

    public void setElementNames(Vector names) {

        this.elementNames = names;
    }

    public void setNamespaces(Vector namespaces) {

        if (namespaces == null || namespaces.size() == 0) {
            this.namespaces = null;
        } else {
            this.namespaces = namespaces;
        }
    }

    public void setEntityNames(Vector names) {

        this.entityNames = names;
    }

    public void setAttributeNames(Hashtable names) {

        this.attributeNames = names;
    }

    private String stripPrefix(String name) {

        if (name != null) {
            int index = name.indexOf(':');
            if (index != -1) {
                name = name.substring(index + 1, name.length());
            }
        }
        return name;
    }

    private Vector getAnyElements() {

        Vector elements = new Vector();
        if (schemas != null) {
            for (int i = 0; i < schemas.size(); i++) {
                Vector elems = ((SchemaDocument) schemas.elementAt(i)).getAnyElements();
                if (elems != null) {
                    elements.addAll(elems);
                }
            }
        }
        return elements;
    }

    public Vector getAllElements() {

        if (allElements == null) {
            allElements = new Vector();
            if (schemas != null) {
                for (int i = 0; i < schemas.size(); i++) {
                    Vector elems = ((SchemaDocument) schemas.elementAt(i)).getElements();
                    if (elems != null) {
                        allElements.addAll(elems);
                    }
                }
            }
        }
        return allElements;
    }

    private Vector getAttributeNames() {

        Vector attributes = null;
        if (attributeNames != null) {
            attributes = new Vector(attributeNames.keySet());
        } else {
            attributes = new Vector();
        }
        attributes.addAll(getAnyAttributeNames());
        return attributes;
    }

    // Returns the elements as been defined in the document.
    public Vector getElementNames() {

        Vector elements = null;
        if (elementNames != null) {
            elements = new Vector(elementNames);
            elements.addAll(getAnyChildElementNames());
        } else {
            elements = new Vector();
        }
        return elements;
    }

    private Vector getAnyAttributes() {

        Vector anyElements = getAnyElements();
        Vector attributes = new Vector();
        for (int i = 0; i < anyElements.size(); i++) {
            Vector attribs = ((ElementInformation) anyElements.elementAt(i)).getAttributes();
            if (attribs != null) {
                for (int j = 0; j < attribs.size(); j++) {
                    if (!attributes.contains(attribs.elementAt(j))) {
                        attributes.addElement(attribs.elementAt(j));
                    }
                }
            }
        }
        return attributes;
    }

    private Vector getAnyAttributeNames() {

        Vector anyElements = getAnyElements();
        Vector attributes = new Vector();
        for (int i = 0; i < anyElements.size(); i++) {
            Vector attribs = ((ElementInformation) anyElements.elementAt(i)).getAttributes();
            for (int j = 0; j < attribs.size(); j++) {
                attributes.addElement(((AttributeInformation) attribs.elementAt(j)).getQualifiedName());
            }
        }
        return attributes;
    }

    private Vector getAnyChildElements() {

        Vector anyElements = getAnyElements();
        Vector elements = new Vector();
        for (int i = 0; i < anyElements.size(); i++) {
            Vector children = ((ElementInformation) anyElements.elementAt(i)).getChildElements();
            if (children != null) {
                elements.addAll(children);
            }
        }
        return elements;
    }

    private Vector getAnyChildElements(SchemaDocument schema) {

        Vector anyElements = schema.getAnyElements();
        Vector elements = new Vector();
        if (anyElements != null) {
            for (int i = 0; i < anyElements.size(); i++) {
                Vector children = ((ElementInformation) anyElements.elementAt(i)).getChildElements();
                if (children != null) {
                    elements.addAll(children);
                }
            }
        }
        return elements;
    }

    private Vector getAnyChildElementNames() {

        Vector anyElements = getAnyElements();
        Vector elements = new Vector();
        for (int i = 0; i < anyElements.size(); i++) {
            Vector elems = ((ElementInformation) anyElements.elementAt(i)).getChildElements();
            for (int j = 0; j < elems.size(); j++) {
                elements.addElement(((ElementInformation) elems.elementAt(j)).getQualifiedName());
            }
        }
        return elements;
    }

    private ElementInformation getElement(Tag parent, Tag child) {

        String parentName = parent.getQualifiedName();
        Vector elements = getAllElements();
        for (int i = 0; i < elements.size(); i++) {
            ElementInformation model = (ElementInformation) elements.elementAt(i);
            if (parentName.equals(model.getQualifiedName())) {
                Vector children = model.getChildElements();
                for (int j = 0; j < children.size(); j++) {
                    ElementInformation element = (ElementInformation) children.elementAt(j);
                    if (child.getQualifiedName().equals(element.getQualifiedName())) {
                        return element;
                    }
                }
            }
        }
        return null;
    }

    private ElementInformation getElement(SchemaDocument schema, Tag parent, Tag child) {

        String parentName = parent.getQualifiedName();
        Vector elements = schema.getElements();
        //      System.out.println( "getChildElements( "+URLUtilities.getFileName(
        // schema.getURL())+", "+parent.getQualifiedName()+",
        // "+child.getQualifiedName()+")");
        for (int i = 0; i < elements.size(); i++) {
            ElementInformation model = (ElementInformation) elements.elementAt(i);
            if (parentName.equals(model.getQualifiedName())) {
                Vector children = model.getChildElements();
                for (int j = 0; j < children.size(); j++) {
                    ElementInformation element = (ElementInformation) children.elementAt(j);
                    if (child.getQualifiedName().equals(element.getQualifiedName())) {
                        return element;
                    }
                }
            }
        }
        return null;
    }

    // Finds the correct child element for a tag.
    private ElementInformation getElement(SchemaDocument schema, Tag child) {

        Vector elements = schema.getElements();
        String name = child.getQualifiedName();
        //      System.out.println( "getElement( "+URLUtilities.getFileName(
        // schema.getURL())+", "+child.getQualifiedName()+")");
        for (int i = 0; i < elements.size(); i++) {
            ElementInformation model = (ElementInformation) elements.elementAt(i);
            if (name.equals(model.getQualifiedName())) {
                Tag parent = getParentStartTag(child);
                // Found an element, know this element is in this schema.
                // Now get the correct element based on it's parent.
                while (parent != null) {
                    ElementInformation element = getElement(schema, parent, child);
                    if (element != null) {
                        return element;
                    }
                    parent = getParentStartTag(parent);
                }
                return model;
            }
        }
        return null;
    }

    private Vector getChildElements(SchemaDocument schema, Tag tag) {

        Vector result = new Vector();
        while (tag != null) {
            ElementInformation element = getElement(schema, tag);
            if (element != null) {
                result.addAll(element.getChildElements());
                break;
            }
            tag = getParentStartTag(tag);
        }
        if (tag == null) {
            result.addAll(schema.getGlobalElements());
        }
        result.addAll(getAnyChildElements(schema));
        return result;
    }

    private Vector getChildElements(SchemaDocument schema) {

        return getChildElements(schema, getParentStartTag());
    }

    private Vector getAttributes() {

        Vector result = new Vector();
        Tag child = getCurrentTag();
        Tag tag = getCurrentStartTag();
        if (child == null) {
            child = tag;
            tag = getParentStartTag();
        }
        while (tag != null) {
            ElementInformation element = getElement(tag, child);
            if (element != null) {
                result.add(element.getAttributes());
                break;
            }
            tag = getParentStartTag(tag);
        }
        // could not find tag...
        if (child != null && tag == null) {
            Vector elements = getAllElements();
            for (int i = 0; i < elements.size(); i++) {
                ElementInformation model = (ElementInformation) elements.elementAt(i);
                if (child.getQualifiedName().equals(model.getQualifiedName())) {
                    result.add(model.getAttributes());
                    break;
                }
            }
        }
        result.add(getAnyAttributes());
        return result;
    }

    private SchemaDocument getCurrentSchema() {

        Tag tag = getParentStartTag();
        SchemaDocument schema = null;
        if (schemas != null && schemas.size() > 0 && tag != null) {
            schema = (SchemaDocument) schemas.elementAt(0);
            if (schemas.size() > 1) {
                for (int i = 0; i < schemas.size(); i++) {
                    Vector elements = ((SchemaDocument) schemas.elementAt(i)).getElements();
                    for (int j = 0; j < elements.size(); j++) {
                        if (((ElementInformation) elements.elementAt(j)).getQualifiedName()
                                .equals(tag.getQualifiedName())) {
                            return (SchemaDocument) schemas.elementAt(i);
                        }
                    }
                }
            } else {
                return schema;
            }
        }
        return null;
    }

    private Vector getChildElements() {

        Vector result = new Vector();
        SchemaDocument currentSchema = getCurrentSchema();
        if (currentSchema != null) {
            result.add(getChildElements(currentSchema));
        }
        if (schemas != null) {
            for (int i = 0; i < schemas.size(); i++) {
                if (schemas.elementAt(i) != currentSchema) {
                    result.add(getChildElements((SchemaDocument) schemas.elementAt(i)));
                }
            }
        }
        return result;
    }

    public void getCurrentElement(CurrentElementListener listener) {

        examiner.getCurrentElement(listener);
    }

    public void getCurrentSiblings(CurrentSiblingsListener listener) {

        examiner.getCurrentSiblings(listener);
    }

    public void getCurrentElements(CurrentElementsListener listener) {

        examiner.getCurrentElements(listener);
    }

    public void getCurrentAttributes(CurrentAttributesListener listener) {

        examiner.getCurrentAttributes(listener);
    }

    private Vector getAttributeValues(String qname) {

        //      System.out.println( "getAttributeValues( "+qname+")");
        String attributeName = stripPrefix(qname);
        Tag child = getCurrentTag();
        Tag tag = getCurrentStartTag();
        if (document.isXSD()) {
            if (attributeName.equals("ref")) {
                if (child.getName().equals("attributeGroup")) {
                    XElement root = document.getLastRoot();
                    if (root != null) {
                        String targetNS = root.getAttribute("targetNamespace");
                        String prefix = null;
                        if (targetNS != null && targetNS.length() > 0) {
                            Namespace ns = root.getNamespaceForURI(targetNS);
                            prefix = ns.getPrefix();
                        }
                        XElement[] elements = root.getElements("attributeGroup");
                        Vector results = new Vector();
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                if (prefix != null && prefix.length() > 0) {
                                    results.addElement(
                                            new AttributeValue(prefix + ":" + value, AttributeValue.NORMAL_TYPE));
                                } else {
                                    results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                                }
                            }
                        }
                        return results;
                    }
                } else if (child.getName().equals("attribute")) {
                    XElement root = document.getLastRoot();
                    if (root != null) {
                        String targetNS = root.getAttribute("targetNamespace");
                        String prefix = null;
                        if (targetNS != null && targetNS.length() > 0) {
                            Namespace ns = root.getNamespaceForURI(targetNS);
                            prefix = ns.getPrefix();
                        }
                        XElement[] elements = root.getElements("attribute");
                        Vector results = new Vector();
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                if (prefix != null && prefix.length() > 0) {
                                    results.addElement(
                                            new AttributeValue(prefix + ":" + value, AttributeValue.NORMAL_TYPE));
                                } else {
                                    results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                                }
                            }
                        }
                        return results;
                    }
                } else if (child.getName().equals("element")) {
                    XElement root = document.getLastRoot();
                    if (root != null) {
                        String targetNS = root.getAttribute("targetNamespace");
                        String prefix = null;
                        if (targetNS != null && targetNS.length() > 0) {
                            Namespace ns = root.getNamespaceForURI(targetNS);
                            prefix = ns.getPrefix();
                        }
                        XElement[] elements = root.getElements("element");
                        Vector results = new Vector();
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                if (prefix != null && prefix.length() > 0) {
                                    results.addElement(
                                            new AttributeValue(prefix + ":" + value, AttributeValue.NORMAL_TYPE));
                                } else {
                                    results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                                }
                            }
                        }
                        return results;
                    }
                } else if (child.getName().equals("group")) {
                    XElement root = document.getLastRoot();
                    if (root != null) {
                        String targetNS = root.getAttribute("targetNamespace");
                        String prefix = null;
                        if (targetNS != null && targetNS.length() > 0) {
                            Namespace ns = root.getNamespaceForURI(targetNS);
                            prefix = ns.getPrefix();
                        }
                        XElement[] elements = root.getElements("group");
                        Vector results = new Vector();
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                if (prefix != null && prefix.length() > 0) {
                                    results.addElement(
                                            new AttributeValue(prefix + ":" + value, AttributeValue.NORMAL_TYPE));
                                } else {
                                    results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                                }
                            }
                        }
                        return results;
                    }
                }
            } else if (attributeName.equals("base")) {
                Tag parent = getParentStartTag(child);
                if (parent != null
                        && (parent.getName().equals("simpleContent") || parent.getName().equals("simpleType"))) {
                    Vector results = getSimpleTypeValues();
                    XElement root = document.getLastRoot();
                    if (root != null) {
                        String targetNS = root.getAttribute("targetNamespace");
                        String prefix = null;
                        if (targetNS != null && targetNS.length() > 0) {
                            Namespace ns = root.getNamespaceForURI(targetNS);
                            prefix = ns.getPrefix();
                        }
                        XElement[] elements = root.getElements("simpleType");
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                if (prefix != null && prefix.length() > 0) {
                                    results.addElement(
                                            new AttributeValue(prefix + ":" + value, AttributeValue.NORMAL_TYPE));
                                } else {
                                    results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                                }
                            }
                        }
                    }
                    return results;
                } else {
                    Vector results = new Vector();
                    XElement root = document.getLastRoot();
                    if (root != null) {
                        String targetNS = root.getAttribute("targetNamespace");
                        String prefix = null;
                        if (targetNS != null && targetNS.length() > 0) {
                            Namespace ns = root.getNamespaceForURI(targetNS);
                            prefix = ns.getPrefix();
                        }
                        XElement[] elements = root.getElements("complexType");
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                if (prefix != null && prefix.length() > 0) {
                                    results.addElement(
                                            new AttributeValue(prefix + ":" + value, AttributeValue.NORMAL_TYPE));
                                } else {
                                    results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                                }
                            }
                        }
                        return results;
                    }
                }
            } else if (attributeName.equals("type")) {
                if (child != null && (child.getName().equals("attribute"))) {
                    Vector results = getSimpleTypeValues();
                    XElement root = document.getLastRoot();
                    if (root != null) {
                        String targetNS = root.getAttribute("targetNamespace");
                        String prefix = null;
                        if (targetNS != null && targetNS.length() > 0) {
                            Namespace ns = root.getNamespaceForURI(targetNS);
                            prefix = ns.getPrefix();
                        }
                        XElement[] elements = root.getElements("simpleType");
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                if (prefix != null && prefix.length() > 0) {
                                    results.addElement(
                                            new AttributeValue(prefix + ":" + value, AttributeValue.NORMAL_TYPE));
                                } else {
                                    results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                                }
                            }
                        }
                    }
                    return results;
                } else if (child != null && (child.getName().equals("element"))) {
                    Vector results = getSimpleTypeValues();
                    XElement root = document.getLastRoot();
                    if (root != null) {
                        String targetNS = root.getAttribute("targetNamespace");
                        String prefix = null;
                        if (targetNS != null && targetNS.length() > 0) {
                            Namespace ns = root.getNamespaceForURI(targetNS);
                            prefix = ns.getPrefix();
                        }
                        XElement[] elements = root.getElements("simpleType");
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                if (prefix != null && prefix.length() > 0) {
                                    results.addElement(
                                            new AttributeValue(prefix + ":" + value, AttributeValue.NORMAL_TYPE));
                                } else {
                                    results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                                }
                            }
                        }
                        elements = root.getElements("complexType");
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                if (prefix != null && prefix.length() > 0) {
                                    results.addElement(
                                            new AttributeValue(prefix + ":" + value, AttributeValue.NORMAL_TYPE));
                                } else {
                                    results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                                }
                            }
                        }
                    }
                    return results;
                }
            }
        } else if (document.isRNG()) {
            if (attributeName.equals("name")) {
                if (child.getName().equals("ref")) {
                    XElement root = document.getLastRoot();
                    Vector results = new Vector();
                    if (root != null) {
                        XElement[] elements = root.getElements("define");
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                            }
                        }
                    }
                    return results;
                }
            } else if (attributeName.equals("type")) {
                Vector results = new Vector();
                for (int i = 0; i < XSD_SIMPLE_TYPES.length; i++) {
                    results.addElement(new AttributeValue(XSD_SIMPLE_TYPES[i], AttributeValue.NORMAL_TYPE));
                }
                return results;
            }
        } else if (document.isXSL()) {
            if (attributeName.equals("name")) {
                if (child.getName().equals("call-template")) {
                    XElement root = document.getLastRoot();
                    Vector results = new Vector();
                    if (root != null) {
                        XElement[] elements = root.getElements("template");
                        for (int i = 0; i < elements.length; i++) {
                            String value = elements[i].getAttribute("name");
                            if (value != null && value.length() > 0) {
                                results.addElement(new AttributeValue(value, AttributeValue.NORMAL_TYPE));
                            }
                        }
                    }
                    return results;
                }
            } else {
                String val = ((XmlDocument) getEditor().getDocument()).getAttributeValue(getCursorPosition());
                int index = val.lastIndexOf('$');
                if (index != -1) {
                    Vector results = new Vector();
                    XElement root = document.getLastRoot();
                    String prefix = "xsl";
                    if (root != null) {
                        Namespace ns = root.getNamespaceForURI("http://www.w3.org/1999/XSL/Transform");
                        prefix = ns.getPrefix();
                    }
                    Vector elements = document
                            .searchLastWellFormedDocument("//" + prefix + ":param | //" + prefix + ":variable");
                    for (int i = 0; i < elements.size(); i++) {
                        XElement element = (XElement) elements.elementAt(i);
                        String value = element.getAttribute("name");
                        if (value != null && value.length() > 0) {
                            results.addElement(new AttributeValue("$" + value, AttributeValue.NORMAL_TYPE));
                        }
                    }
                    return results;
                }
            }
        }
        while (tag != null) {
            ElementInformation element = getElement(tag, child);
            if (element != null) {
                Vector attributes = element.getAttributes();

                //tcurley - fixed this bug which caused an infinite loop
                //of null pointer exceptions
                if (attributes != null) {

                    attributes.addAll(getAnyAttributes());

                    for (int k = 0; k < attributes.size(); k++) {
                        AttributeInformation a = (AttributeInformation) attributes.elementAt(k);
                        if (a.getName().equals(attributeName)) {
                            Vector results = new Vector();
                            Vector values = a.getValues();
                            if (attributeNames != null) {
                                Vector otherValues = (Vector) attributeNames.get(qname);
                                if (otherValues != null) {
                                    for (int i = 0; i < otherValues.size(); i++) {
                                        if (!contains(values, (String) otherValues.elementAt(i))) {
                                            results.addElement(new AttributeValue((String) otherValues.elementAt(i),
                                                    AttributeValue.NORMAL_TYPE));
                                        }
                                    }
                                }
                            }
                            if (values != null) {
                                for (int i = 0; i < values.size(); i++) {
                                    results.addElement(values.elementAt(i));
                                }
                            }
                            return results;
                        }
                    }
                    if (attributeNames != null) {
                        Vector otherValues = (Vector) attributeNames.get(qname);
                        if (otherValues != null) {
                            Vector results = new Vector();
                            for (int i = 0; i < otherValues.size(); i++) {
                                results.addElement(new AttributeValue((String) otherValues.elementAt(i),
                                        AttributeValue.NORMAL_TYPE));
                            }
                            return results;
                        }
                    }
                    return null;
                }
            }
            tag = getParentStartTag(tag);
        }
        if (attributeNames != null) {
            Vector otherValues = (Vector) attributeNames.get(qname);
            if (otherValues != null) {
                Vector results = new Vector();
                for (int i = 0; i < otherValues.size(); i++) {
                    results.addElement(
                            new AttributeValue((String) otherValues.elementAt(i), AttributeValue.NORMAL_TYPE));
                }
                return results;
            }
        }
        return null;
    }

    private boolean contains(Vector values, String value) {

        if (values != null) {
            for (int i = 0; i < values.size(); i++) {
                if (value.equals(((AttributeValue) values.elementAt(i)).getValue())) {
                    return true;
                }
            }
        }
        return false;
    }

    private Vector getSimpleTypeValues() {

        Vector result = new Vector();
        XElement root = document.getLastRoot();
        String prefix = "xsd";
        if (root != null) {
            Namespace ns = root.getNamespaceForURI("http://www.w3.org/2001/XMLSchema");
            prefix = ns.getPrefix();
        }
        for (int i = 0; i < XSD_SIMPLE_TYPES.length; i++) {
            if (prefix != null && prefix.length() > 0) {
                result.add(new AttributeValue(prefix + ":" + XSD_SIMPLE_TYPES[i], AttributeValue.NORMAL_TYPE));
            } else {
                result.add(new AttributeValue(XSD_SIMPLE_TYPES[i], AttributeValue.NORMAL_TYPE));
            }
        }
        return result;
    }

    // Shows the attribute selection popup
    private void showElementSelectionPopup(final String prefix, final Vector children, final String parent) {

        //      System.out.println( "showElementSelectionPopup( "+prefix+",
        // "+parent+")");
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                try {
                    if (prefix.startsWith("/")) {
                        Vector names = new Vector();
                        names.addElement(parent);
                        selectionPopup.setElementNames(names, prefix, parent);
                    } else {
                        Vector elements = getAllElements();
                        if (elements != null && elements.size() > 0) { // there
                                                                       // is a
                                                                       // schema
                                                                       // available.
                            selectionPopup.setElements(children, prefix, parent);
                        } else { // no schema available so only set previous
                                 // names
                            selectionPopup.setElementNames(getElementNames(), prefix, parent);
                        }
                    }
                    if (selectionPopup.getNames() > 1 || (selectionPopup.getNames() == 1
                            && !prefix.equals(selectionPopup.getSelectedName()))) {
                        int caretPos = getEditor().getCaretPosition();
                        Rectangle pos = getEditor().modelToView(caretPos);
                        FontMetrics fm = getEditor().getFontMetrics(getEditor().getFont());
                        int height = fm.getHeight();
                        int width = fm.getWidths()[0];
                        selectionPopup.show(getEditor(), pos.x - (prefix.length() * width), pos.y + height);
                        getEditor().requestFocusInWindow();
                    }
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    // Shows the attribute selection popup
    private void showDeclarationSelectionPopup(final Vector names, final String prefix) {

        //      System.out.println( "showDeclarationSelectionPopup( "+names+",
        // "+prefix+")");
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                try {
                    selectionPopup.setDeclarationNames(names, prefix);
                    if (selectionPopup.getNames() > 1 || (selectionPopup.getNames() == 1
                            && !prefix.equals(selectionPopup.getSelectedName()))) {
                        int caretPos = getEditor().getCaretPosition();
                        Rectangle pos = getEditor().modelToView(caretPos);
                        FontMetrics fm = getEditor().getFontMetrics(getEditor().getFont());
                        int height = fm.getHeight();
                        int width = fm.getWidths()[0];
                        selectionPopup.show(getEditor(), pos.x - (prefix.length() * width), pos.y + height);
                        getEditor().requestFocusInWindow();
                    }
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void showElementDeclarationSelectionPopup(Tag elementDeclarationTag, int offset, String value) {

        //      System.out.println( "showElementDeclarationSelectionPopup(
        // "+elementDeclarationTag+", "+offset+", "+value+")");
        Vector values = elementDeclarationTag.getValues(offset);
        if (values.size() > 2 && value != null && value.length() > 0) { // last
                                                                        // item
                                                                        // in
                                                                        // values
                                                                        // ==
                                                                        // value
            if (value.endsWith("(") || value.endsWith("|") || value.endsWith(",")) {
                Vector pcdata = new Vector();
                pcdata.addElement("#PCDATA");
                showDeclarationSelectionPopup(pcdata, "");
            } else {
                StringTokenizer tokenizer = new StringTokenizer(value, "(|,");
                String lastToken = null;
                while (tokenizer.hasMoreTokens()) {
                    lastToken = tokenizer.nextToken();
                }
                if ("#PCDATA".startsWith(lastToken)) {
                    Vector pcdata = new Vector();
                    pcdata.addElement("#PCDATA");
                    showDeclarationSelectionPopup(pcdata, lastToken);
                } else {
                    showDeclarationSelectionPopup(getElementDeclarationTypes(), value);
                }
            }
        } else if (values.size() == 2) { // the values do not contain the current
                                         // value
            showDeclarationSelectionPopup(getElementDeclarationTypes(), value);
        }
    }

    private void showNotationDeclarationSelectionPopup(Tag elementDeclarationTag, int offset, String value) {

        //      System.out.println( "showNotationDeclarationSelectionPopup(
        // "+elementDeclarationTag+", "+offset+", "+value+")");
        Vector values = elementDeclarationTag.getValues(offset);
        if (values.size() == 3 && value != null && value.length() > 0) { // last
                                                                         // item
                                                                         // in
                                                                         // values
                                                                         // ==
                                                                         // value
            showDeclarationSelectionPopup(getNotationDeclarationTypes(), value);
        } else if (values.size() == 2 && (value == null || value.length() == 0)) { // the
                                                                                   // values
                                                                                   // do
                                                                                   // not
                                                                                   // contain
                                                                                   // the
                                                                                   // current
                                                                                   // value
            showDeclarationSelectionPopup(getNotationDeclarationTypes(), value);
        }
    }

    private void showEntityDeclarationSelectionPopup(Tag elementDeclarationTag, int offset, String value) {

        //      System.out.println( "showEntityDeclarationSelectionPopup(
        // "+elementDeclarationTag+", "+offset+", "+value+")");
        Vector values = elementDeclarationTag.getValues(offset);
        if (values.size() == 3 && value != null && value.length() > 0 && !values.elementAt(1).equals("%")) { // last item in values
                                                                                                             // == value
            showDeclarationSelectionPopup(getNotationDeclarationTypes(), value); // SYSTEM,
                                                                                 // PUBLIC
        } else if (values.size() == 2 && !values.elementAt(1).equals("%")
                && (value == null || value.length() == 0)) { // the values do
                                                                                                                               // not contain the
                                                                                                                               // current value
            showDeclarationSelectionPopup(getNotationDeclarationTypes(), value);
        } else if (values.size() == 4 && value != null && value.length() > 0 && values.elementAt(1).equals("%")) { // last item in values ==
                                                                                                                   // value
            showDeclarationSelectionPopup(getNotationDeclarationTypes(), value); // SYSTEM,
                                                                                 // PUBLIC
        } else if (values.size() == 3 && values.elementAt(1).equals("%")
                && (value == null || value.length() == 0)) { // the values do
                                                                                                                              // not contain the
                                                                                                                              // current value
            showDeclarationSelectionPopup(getNotationDeclarationTypes(), value);
        } else if (values.size() == 4 && (value == null || value.length() == 0)
                && !values.elementAt(1).equals("%")) { // last item in values
                                                                                                                               // == value
            Vector ndata = new Vector();
            ndata.addElement("NDATA");
            showDeclarationSelectionPopup(ndata, value); // SYSTEM, PUBLIC
        } else if (values.size() > 4 && !values.elementAt(1).equals("%")) { // last
                                                                            // item
                                                                            // in
                                                                            // values
                                                                            // ==
                                                                            // value
            Vector ndata = new Vector();
            ndata.addElement("NDATA");
            showDeclarationSelectionPopup(ndata, value); // SYSTEM, PUBLIC
        }
    }

    private void showDoctypeDeclarationSelectionPopup(Tag elementDeclarationTag, int offset, String value) {

        //      System.out.println( "showDoctypeDeclarationSelectionPopup(
        // "+elementDeclarationTag+", "+offset+", "+value+")");
        Vector values = elementDeclarationTag.getValues(offset);
        if (values.size() == 3 && value != null && value.length() > 0) { // last
                                                                         // item
                                                                         // in
                                                                         // values
                                                                         // ==
                                                                         // value
            if (value.equals("[")) {
                getEditor().replaceSelection("]>");
                getEditor().setCaretPosition(getEditor().getCaretPosition() - 2);
            } else {
                showDeclarationSelectionPopup(getNotationDeclarationTypes(), value);
            }
        } else if (values.size() == 2 && (value == null || value.length() == 0)) { // the
                                                                                   // values
                                                                                   // do
                                                                                   // not
                                                                                   // contain
                                                                                   // the
                                                                                   // current
                                                                                   // value
            showDeclarationSelectionPopup(getNotationDeclarationTypes(), value);
        }
    }

    private void showAttlistDeclarationSelectionPopup(Tag elementDeclarationTag, int offset, String value) {

        //      System.out.println( "showAttlistDeclarationSelectionPopup(
        // "+elementDeclarationTag+", "+offset+", "+value+")");
        Vector values = elementDeclarationTag.getValues(offset);
        boolean hasEntity = false;
        for (int i = 0; (i < values.size()) && (i < 4); i++) {
            if (isEntity((String) values.elementAt(i))) {
                hasEntity = true;
            }
        }
        if (!hasEntity) {
            if (values.size() == 4 && value != null && value.length() > 0) { // last
                                                                             // item
                                                                             // in
                                                                             // values
                                                                             // ==
                                                                             // value
                showDeclarationSelectionPopup(getAttlistDeclarationTypes(), value);
            } else if (values.size() == 3 && (value == null || value.length() == 0)) { // the values
                                                                                       // do not
                                                                                       // contain the
                                                                                       // current
                                                                                       // value
                showDeclarationSelectionPopup(getAttlistDeclarationTypes(), value);
            } else if (values.size() == 5 && value != null && value.length() > 0) { // last
                                                                                    // item
                                                                                    // in
                                                                                    // values
                                                                                    // ==
                                                                                    // value
                showDeclarationSelectionPopup(getAttlistDeclarationDefaults(), value);
            } else if (values.size() == 4 && (value == null || value.length() == 0)) { // the values
                                                                                       // do not
                                                                                       // contain the
                                                                                       // current
                                                                                       // value
                showDeclarationSelectionPopup(getAttlistDeclarationDefaults(), value);
            } else if (values.size() > 5) {
                String previousValue = null;
                if (value == null || value.length() == 0) {
                    previousValue = (String) values.elementAt(values.size() - 1);
                } else {
                    previousValue = (String) values.elementAt(values.size() - 2);
                }
                if (isEntity(previousValue)) {
                    showDeclarationSelectionPopup(getAttlistDeclarationAll(), value);
                } else if (isAttlistType(previousValue)) {
                    showDeclarationSelectionPopup(getAttlistDeclarationDefaults(), value);
                } else if (!isAttlistDefault(previousValue)) {
                    showDeclarationSelectionPopup(getAttlistDeclarationTypes(), value);
                }
            }
        } else if (values.size() > 1) {
            String previousValue = null;
            if (value == null || value.length() == 0) {
                previousValue = (String) values.elementAt(values.size() - 1);
            } else {
                previousValue = (String) values.elementAt(values.size() - 2);
            }
            if (isEntity(previousValue)) {
                showDeclarationSelectionPopup(getAttlistDeclarationAll(), value);
            } else if (isAttlistType(previousValue) || previousValue.endsWith(")")) {
                showDeclarationSelectionPopup(getAttlistDeclarationDefaults(), value);
            } else if (!isAttlistDefault(previousValue)) {
                showDeclarationSelectionPopup(getAttlistDeclarationTypes(), value);
            }
        }
    }

    private boolean isEntity(String value) {

        if (value != null && value.startsWith("%") && value.endsWith(";")) {
            return true;
        }
        return false;
    }

    private boolean isAttlistType(String type) {

        Vector types = getAttlistDeclarationTypes();
        if (type != null) {
            for (int i = 0; i < types.size(); i++) {
                if (types.elementAt(i).equals(type)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isAttlistDefault(String def) {

        Vector defaults = getAttlistDeclarationDefaults();
        if (def != null) {
            for (int i = 0; i < defaults.size(); i++) {
                if (defaults.elementAt(i).equals(def)) {
                    return true;
                }
            }
        }
        return false;
    }

    // Shows the attribute selection popup
    private void showEntitySelectionPopup(final String prefix) {

        //      System.out.println( "showEntitySelectionPopup( "+prefix+")");
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                try {
                    //                  System.out.println( "showEntitySelectionPopup(
                    // "+prefix+")");
                    selectionPopup.setEntities(prefix);
                    if (selectionPopup.getNames() > 1 || (selectionPopup.getNames() == 1
                            && !prefix.equals(selectionPopup.getSelectedName()))) {
                        int caretPos = getEditor().getCaretPosition();
                        Rectangle pos = getEditor().modelToView(caretPos);
                        FontMetrics fm = getEditor().getFontMetrics(getEditor().getFont());
                        int height = fm.getHeight();
                        int width = fm.getWidths()[0];
                        selectionPopup.show(getEditor(), pos.x - (prefix.length() * width), pos.y + height);
                        getEditor().requestFocusInWindow();
                    }
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    // Hides the selection popup
    private void hideSelectionPopup() {

        //       System.out.println( "hideSelectionPopup()");
        if (selectionPopup.isVisible()) {
            selectionPopup.setVisible(false);
        }
    }

    private ValuesPopupListener getValuesPopupListener(String prefix) {

        if (valuesPopupListener == null) {
            valuesPopupListener = new ValuesPopupListener();
        }
        valuesPopupListener.setPrefix(prefix);
        return valuesPopupListener;
    }

    private void showAttributeValueSelectionPopup(final String prefix, final Vector values) {

        //if (DEBUG) System.out.println(
        // "Editor.showAttributeValueSelectionPopup( "+prefix+", "+parent+")");
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                try {
                    selectionPopup.setAttributeValues(values, prefix);
                    if (selectionPopup.getNames() > 1 || (selectionPopup.getNames() == 1
                            && !prefix.equals(selectionPopup.getSelectedName()))) {
                        int caretPos = getEditor().getCaretPosition();
                        Rectangle pos = getEditor().modelToView(caretPos);
                        FontMetrics fm = getEditor().getFontMetrics(getEditor().getFont());
                        int height = fm.getHeight();
                        int width = fm.getWidths()[0];
                        selectionPopup.show(getEditor(), pos.x - (prefix.length() * width), pos.y + height);
                        getEditor().requestFocusInWindow();
                    }
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private AttributesPopupListener getAttributesPopupListener(String prefix, Tag tag) {

        if (attributesPopupListener == null) {
            attributesPopupListener = new AttributesPopupListener();
        }
        attributesPopupListener.setPrefix(prefix);
        attributesPopupListener.setTag(tag);
        return attributesPopupListener;
    }

    private ElementsPopupListener getElementsPopupListener(String prefix, String parent) {

        if (elementsPopupListener == null) {
            elementsPopupListener = new ElementsPopupListener();
        }
        elementsPopupListener.setPrefix(prefix);
        elementsPopupListener.setParent(parent);
        return elementsPopupListener;
    }

    // Shows the attribute selection popup
    private void showAttributeSelectionPopup(final String prefix, final Vector attributes, final Tag tag) {

        if (DEBUG)
            System.out.println(
                    "Editor.showAttributeSelectionPopup( " + prefix + ", " + attributes + ", " + tag + ")");
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                try {
                    Vector elements = getAllElements();
                    if (elements != null && elements.size() > 0) { // there is
                                                                   // a schema
                                                                   // available.
                        selectionPopup.setAttributes(attributes, prefix, tag.getAttributeNames(), namespaces);
                    } else {
                        selectionPopup.setAttributeNames(getAttributeNames(), prefix, tag.getAttributeNames(),
                                namespaces);
                    }
                    if (selectionPopup.getNames() > 1 || (selectionPopup.getNames() == 1
                            && !prefix.equals(selectionPopup.getSelectedName()))) {
                        int caretPos = getEditor().getCaretPosition();
                        Rectangle pos = getEditor().modelToView(caretPos);
                        FontMetrics fm = getEditor().getFontMetrics(getEditor().getFont());
                        int height = fm.getHeight();
                        int width = fm.getWidths()[0];
                        selectionPopup.show(getEditor(), pos.x - (prefix.length() * width), pos.y + height);
                        getEditor().requestFocusInWindow();
                    }
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public Point getPosition() {

        Element root = getEditor().getDocument().getDefaultRootElement();
        int line = root.getElementIndex(getCursorPosition());
        int start = root.getElement(line).getStartOffset();
        int col = getCursorPosition() - start;
        String text = "";
        try {
            text = getEditor().getText(start, col);
        } catch (BadLocationException b) {
        }
        int index = text.indexOf('\t');
        while (index != -1) {
            col = col + (TextPreferences.getTabSize() - 1);
            index = text.indexOf('\t', index + 1);
        }
        return new Point(line + 1, col + 1);
    }

    //   
    //   private int currentStartTagPos = -1;
    //   private Tag currentStartTag = null;
    //   private Tag currentEndTag = null;
    //   
    //   private Tag getCurrentStartTag( int pos) {
    //      
    //      if ( pos != currentStartTagPos) {
    //         XmlDocument doc = (XmlDocument)getEditor().getDocument();
    //         Tag tag = doc.getCurrentTag( pos);
    //         
    //         if ( tag != null && (tag.getType() == Tag.START_TAG || tag.getType() ==
    // Tag.EMPTY_TAG)) {
    //            currentStartTag = tag;
    //         } else {
    //            currentStartTag = doc.getParentStartTag( pos);
    //         }
    //         
    //         currentEndTag = null;
    //      }
    //      
    //      currentStartTagPos = pos;
    //
    //      return currentStartTag;
    //   }
    //
    //   public Tag getEndTag( Tag startTag) {
    //      
    //      if ( startTag == currentStartTag && currentEndTag != null) {
    //         return currentEndTag;
    //      } else {
    //         XmlDocument doc = (XmlDocument)getEditor().getDocument();
    //         Tag tag = null;
    //   
    //         if ( startTag != null && startTag.getType() == Tag.START_TAG) {
    //            tag = doc.getEndTag( startTag);
    //         }
    //         
    //         if ( startTag == currentStartTag) {
    //            currentEndTag = tag;
    //         }
    //   
    //         return tag;
    //      }
    //   }
    public void collapseAll() {

        selectedEditor.getFoldingMargin().foldAll();
    }

    public void expandAll() {

        selectedEditor.getFoldingMargin().unfoldAll();
    }

    public void updateHelper() {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        int caretPos = getEditor().getCaretPosition();
        int selectionStart = getEditor().getSelectionStart();
        int selectionEnd = getEditor().getSelectionEnd();
        Tag tag = getCurrentTag();
        parent.getLockAction().setUnlock(getEditor().getLocked());
        parent.getCollapseAllAction().setEnabled(selectedEditor.getFoldingMargin().isVisible());
        parent.getExpandAllAction().setEnabled(selectedEditor.getFoldingMargin().isVisible());
        // No range has been selected
        if (caretPos == selectionStart && caretPos == selectionEnd) {
            //         if ( document.isXML()) {
            parent.getStripTagsAction().setEnabled(false);
            parent.getSubstituteCharactersAction().setEnabled(false);
            parent.getSubstituteEntitiesAction().setEnabled(false);
            parent.getLockAction().setEnabled(true);
            if (!(getEditor().getLocked() == XmlEditorPane.NOT_LOCKED)) {
                parent.getCommentAction().setEnabled(false);
                parent.getRenameElementAction().setEnabled(false);
                parent.getCDATAAction().setEnabled(false);
                parent.getSplitElementAction().setEnabled(false);
                parent.getHelper().setElementsEnabled(false);
                parent.getHelper().setAttributesEnabled(false);
                parent.getTagAction().setEnabled(false);
                parent.getToggleEmptyElementAction().setEnabled(false);
            } else {
                parent.getTagAction().setEnabled(true);
                parent.getCommentAction().setEnabled(true);
                parent.getRenameElementAction().setEnabled(true);
                parent.getCDATAAction().setEnabled(true);
                parent.getHelper().setElementsEnabled(true);
                parent.getHelper().setAttributesEnabled(true);
                if (tag != null) {
                    parent.getSplitElementAction().setEnabled(false);
                    if (tag.getType() == Tag.COMMENT_TAG) {
                        parent.getCommentAction().setUncomment(true);
                    } else {
                        parent.getCommentAction().setUncomment(false);
                    }
                    if (tag.getType() == Tag.EMPTY_TAG) {
                        parent.getToggleEmptyElementAction().setEnabled(true);
                    } else {
                        parent.getToggleEmptyElementAction().setEnabled(false);
                    }
                    if (tag.getType() == Tag.CDATA_TAG) {
                        parent.getCDATAAction().setUnCDATA(true);
                    } else {
                        parent.getCDATAAction().setUnCDATA(false);
                    }
                } else {
                    parent.getToggleEmptyElementAction().setEnabled(false);
                    parent.getSplitElementAction().setEnabled(true);
                    parent.getCommentAction().setUncomment(false);
                    parent.getCDATAAction().setUnCDATA(false);
                }
            }
            //         } else
            if (document.isDTD()) {
                parent.getLockAction().setEnabled(false);
                if (tag != null) {
                    if (tag.getType() == Tag.COMMENT_TAG) {
                        parent.getCommentAction().setUncomment(true);
                    } else {
                        parent.getCommentAction().setUncomment(false);
                    }
                } else {
                    parent.getCommentAction().setUncomment(false);
                }
            } else if (!document.isXML()) {
                //            parent.getToggleEmptyElementAction().setEnabled( false);
                parent.getLockAction().setEnabled(false);
                //            parent.getCommentAction().setUncomment( false);
            }
        } else {
            // There is a selection...
            parent.getCopyAction().setEnabled(true);
            parent.getCutAction().setEnabled(true);
            parent.getToggleEmptyElementAction().setEnabled(false);
            //         if ( document.isXML()) {
            parent.getSplitElementAction().setEnabled(false);
            parent.getLockAction().setEnabled(true);
            if (!(getEditor().getLocked() == XmlEditorPane.NOT_LOCKED)) {
                parent.getStripTagsAction().setEnabled(false);
                parent.getSubstituteCharactersAction().setEnabled(false);
                parent.getSubstituteEntitiesAction().setEnabled(false);
                parent.getCommentAction().setEnabled(false);
                parent.getCDATAAction().setEnabled(false);
                parent.getHelper().setElementsEnabled(false);
                parent.getHelper().setAttributesEnabled(false);
                parent.getTagAction().setEnabled(false);
                parent.getRenameElementAction().setEnabled(false);
            } else {
                parent.getStripTagsAction().setEnabled(true);
                parent.getSubstituteCharactersAction().setEnabled(true);
                parent.getSubstituteEntitiesAction().setEnabled(true);
                parent.getHelper().setElementsEnabled(true);
                parent.getHelper().setAttributesEnabled(true);
                String text = getEditor().getSelectedText();
                Tag startTag = doc.getCurrentTag(selectionStart);
                Tag endTag = doc.getCurrentTag(selectionEnd);
                // does the selection contain CDATA??
                if (text.indexOf("<![CDATA[") != -1 || text.indexOf("]]>") != -1) {
                    parent.getCDATAAction().setEnabled(false);
                } else {
                    parent.getCDATAAction().setEnabled(true);
                }
                // does the selection contain a comment??
                if (text.indexOf("<!--") != -1 || text.indexOf("-->") != -1) {
                    parent.getCommentAction().setEnabled(false);
                } else {
                    parent.getCommentAction().setEnabled(true);
                }
                if ((startTag == null && endTag == null)
                        || (startTag != null && endTag != null && startTag.equals(endTag))) {
                    tag = startTag;
                    if (tag != null) {
                        parent.getHelper().setElementsEnabled(true);
                        parent.getTagAction().setEnabled(true);
                        parent.getRenameElementAction().setEnabled(true);
                        if (tag.getType() == Tag.COMMENT_TAG && parent.getCommentAction().isEnabled()) {
                            parent.getCommentAction().setUncomment(true);
                        } else {
                            parent.getCommentAction().setUncomment(false);
                        }
                        if (tag.getType() == Tag.CDATA_TAG && parent.getCDATAAction().isEnabled()) {
                            parent.getCDATAAction().setUnCDATA(true);
                        } else {
                            parent.getCDATAAction().setUnCDATA(false);
                        }
                    } else {
                        Tag parentStartTag = doc.getParentStartTag(selectionStart);
                        Tag parentEndTag = doc.getParentStartTag(selectionEnd);
                        parent.getCommentAction().setUncomment(false);
                        parent.getCDATAAction().setUnCDATA(false);
                        if (parentStartTag != null && parentStartTag.equals(parentEndTag)) {
                            parent.getHelper().setElementsEnabled(true);
                            parent.getTagAction().setEnabled(true);
                            parent.getRenameElementAction().setEnabled(true);
                        } else if (parentStartTag == null && parentEndTag == null) {
                            parent.getHelper().setElementsEnabled(true);
                            parent.getTagAction().setEnabled(true);
                            parent.getRenameElementAction().setEnabled(true);
                        } else {
                            parent.getHelper().setElementsEnabled(false);
                            parent.getTagAction().setEnabled(false);
                            parent.getRenameElementAction().setEnabled(false);
                        }
                    }
                } else {
                    parent.getCommentAction().setUncomment(false);
                    parent.getCDATAAction().setUnCDATA(false);
                    parent.getHelper().setElementsEnabled(false);
                    parent.getTagAction().setEnabled(false);
                    parent.getRenameElementAction().setEnabled(false);
                    parent.getHelper().setElement((Tag) null);
                }
            }
            //         } else
            if (document.isDTD()) {
                parent.getLockAction().setEnabled(false);
                String text = getEditor().getSelectedText();
                tag = doc.getCurrentTag(selectionStart);
                // does the selection contain a comment??
                if (text.indexOf("<!--") != -1 || text.indexOf("-->") != -1) {
                    parent.getCommentAction().setEnabled(false);
                } else {
                    parent.getCommentAction().setEnabled(true);
                }
                if (tag != null) {
                    if (tag.getType() == Tag.COMMENT_TAG && parent.getCommentAction().isEnabled()) {
                        parent.getCommentAction().setUncomment(true);
                    } else {
                        parent.getCommentAction().setUncomment(false);
                    }
                } else {
                    parent.getCommentAction().setUncomment(false);
                }
            } else if (!document.isXML()) {
                parent.getLockAction().setEnabled(false);
                //            parent.getCommentAction().setUncomment( false);
            }
        }
        if (parent.getHelper().isElementsEnabled()) {
            tag = getCurrentTag();
            if (tag != null) {
                if (tag.getType() == Tag.START_TAG || tag.getType() == Tag.EMPTY_TAG) {
                    parent.getHelper().setElement(tag);
                } else {
                    Tag startTag = getParentStartTag();
                    if (startTag != null) {
                        parent.getHelper().setElement(startTag);
                    } else {
                        parent.getHelper().setElement((Tag) null);
                    }
                }
            } else {
                Tag startTag = getParentStartTag();
                if (startTag != null) {
                    parent.getHelper().setElement(startTag);
                } else {
                    parent.getHelper().setElement((Tag) null);
                }
            }
        }
        updatePosition();
        if (document != null) {
            int nodePos = -1;
            int pos = doc.calculateOldPosition(getCursorPosition());
            //         XElement element = document.getLastElement(
            // doc.calculateOldPosition( getCursorPosition()));
            Object xpathNode = document.getLastNode(pos, true);
            Object node = document.getLastNode(pos, false);
            boolean end = false;
            if (node != null) {
                if (xpathNode instanceof XElement) {
                    parent.getXPathEditor().setXPath((XElement) xpathNode);
                } else {
                    parent.getXPathEditor().setXPath((XAttribute) xpathNode);
                }
                if (node instanceof XElement) {
                    parent.getNavigator().setSelectedElement((XElement) node);
                    if (pos >= ((XElement) node).getContentEndPosition() + 1) {
                        end = true;
                        nodePos = doc.calculateNewPosition(((XElement) node).getContentEndPosition());
                    } else {
                        nodePos = doc.calculateNewPosition(((XElement) node).getElementStartPosition());
                    }
                } else {
                    nodePos = doc.calculateNewPosition(((XAttribute) node).getAttributeStartPosition());
                    parent.getNavigator().setSelectedElement((XElement) ((XAttribute) node).getParent());
                }
                int y = -1;
                try {
                    Rectangle r = getEditor().modelToView(nodePos);
                    if (r != null) {
                        y = r.y;
                        y = y - selectedEditor.getScroller().getViewport().getViewRect().y;
                        if (selectedEditor == bottomEditor) {
                            y = y + (topEditor.getSize().height + split.getDividerSize());
                        }
                    }
                } catch (BadLocationException e) {
                }
                parent.synchronise(view, (Node) node, end, y);
            }
        }
        updateMargins();
        //      bookmarkMargin.revalidate();
        //      bookmarkMargin.repaint();
    }

    private void updatePosition() {

        XmlDocument doc = (XmlDocument) getEditor().getDocument();
        Element root = doc.getDefaultRootElement();
        int pos = getEditor().getCaretPosition();
        int line = root.getElementIndex(pos);
        int start = root.getElement(line).getStartOffset();
        int col = pos - start;
        String text = "";
        try {
            text = getEditor().getText(start, pos - start);
        } catch (BadLocationException b) {
        }
        int index = text.indexOf('\t');
        while (index != -1) {
            col = col + (TextPreferences.getTabSize() - 1);
            index = text.indexOf('\t', index + 1);
        }
        parent.getStatusbar().setPosition(line + 1, col + 1);
    }

    public void updateSplitPane() {

        if (split.getDividerLocation() < split.getMinimumDividerLocation()) {
            split.setOneTouchExpandable(false);
            split.setDividerSize(3);
            Object ui = split.getUI();
            if (ui instanceof BasicSplitPaneUI) {
                ((BasicSplitPaneUI) ui).getDivider()
                        .setBorder(new CompoundBorder(
                                new MatteBorder(1, 0, 0, 0, UIManager.getColor("controlDkShadow")),
                                new MatteBorder(1, 0, 0, 0, Color.white)));
            }
        } else if (split.getDividerLocation() > split.getMaximumDividerLocation()) {
            split.setOneTouchExpandable(false);
            split.setDividerSize(3);
            split.setDividerLocation(split.getDividerLocation() + 3);
            Object ui = split.getUI();
            if (ui instanceof BasicSplitPaneUI) {
                ((BasicSplitPaneUI) ui).getDivider()
                        .setBorder(new CompoundBorder(new MatteBorder(0, 0, 1, 0, Color.white),
                                new MatteBorder(0, 0, 1, 0, UIManager.getColor("controlDkShadow"))));
            }
        } else {
            split.setOneTouchExpandable(true);
            split.setDividerSize(6);
            Object ui = split.getUI();
            if (ui instanceof BasicSplitPaneUI) {
                ((BasicSplitPaneUI) ui).getDivider().setBorder(null);
            }
        }
    }

    private static Vector getAttlistDeclarationAll() {

        if (attlistDeclarationAll == null) {
            attlistDeclarationAll = new Vector();
            attlistDeclarationAll.addElement("CDATA");
            attlistDeclarationAll.addElement("NMTOKEN");
            attlistDeclarationAll.addElement("NMTOKENS");
            attlistDeclarationAll.addElement("ID");
            attlistDeclarationAll.addElement("IDREF");
            attlistDeclarationAll.addElement("IDREFS");
            attlistDeclarationAll.addElement("ENTITY");
            attlistDeclarationAll.addElement("ENTITIES");
            attlistDeclarationAll.addElement("NOTATION");
            attlistDeclarationAll.addElement("#REQUIRED");
            attlistDeclarationAll.addElement("#IMPLIED");
            attlistDeclarationAll.addElement("#FIXED");
        }
        return attlistDeclarationAll;
    }

    private static Vector getAttlistDeclarationTypes() {

        if (attlistDeclarationTypes == null) {
            attlistDeclarationTypes = new Vector();
            attlistDeclarationTypes.addElement("CDATA");
            attlistDeclarationTypes.addElement("NMTOKEN");
            attlistDeclarationTypes.addElement("NMTOKENS");
            attlistDeclarationTypes.addElement("ID");
            attlistDeclarationTypes.addElement("IDREF");
            attlistDeclarationTypes.addElement("IDREFS");
            attlistDeclarationTypes.addElement("ENTITY");
            attlistDeclarationTypes.addElement("ENTITIES");
            attlistDeclarationTypes.addElement("NOTATION");
        }
        return attlistDeclarationTypes;
    }

    private static Vector getAttlistDeclarationDefaults() {

        if (attlistDeclarationDefaults == null) {
            attlistDeclarationDefaults = new Vector();
            attlistDeclarationDefaults.addElement("#REQUIRED");
            attlistDeclarationDefaults.addElement("#IMPLIED");
            attlistDeclarationDefaults.addElement("#FIXED");
        }
        return attlistDeclarationDefaults;
    }

    private static Vector getDeclarationNames() {

        if (declarationNames == null) {
            declarationNames = new Vector();
            //         declarationNames.addElement( "!DOCTYPE");
            declarationNames.addElement("!ELEMENT");
            declarationNames.addElement("!ATTLIST");
            declarationNames.addElement("!ENTITY");
            declarationNames.addElement("!NOTATION");
            declarationNames.addElement("!--");
            declarationNames.addElement("![CDATA[");
        }
        return declarationNames;
    }

    private static Vector getElementDeclarationTypes() {

        if (elementDeclarationTypes == null) {
            elementDeclarationTypes = new Vector();
            elementDeclarationTypes.addElement("(#PCDATA)");
            elementDeclarationTypes.addElement("EMPTY");
            elementDeclarationTypes.addElement("ANY");
        }
        return elementDeclarationTypes;
    }

    private static Vector getEntityDeclarationTypes() {

        if (entityDeclarationTypes == null) {
            entityDeclarationTypes = new Vector();
            entityDeclarationTypes.addElement("SYSTEM");
            entityDeclarationTypes.addElement("PUBLIC");
            entityDeclarationTypes.addElement("NDATA");
        }
        return entityDeclarationTypes;
    }

    private static Vector getDoctypeDeclarationTypes() {

        if (doctypeDeclarationTypes == null) {
            doctypeDeclarationTypes = new Vector();
            doctypeDeclarationTypes.addElement("SYSTEM");
            doctypeDeclarationTypes.addElement("PUBLIC");
        }
        return doctypeDeclarationTypes;
    }

    private static Vector getNotationDeclarationTypes() {

        if (notationDeclarationTypes == null) {
            notationDeclarationTypes = new Vector();
            notationDeclarationTypes.addElement("SYSTEM");
            notationDeclarationTypes.addElement("PUBLIC");
        }
        return notationDeclarationTypes;
    }

    //   public int getCursorLine() {
    //      Element root = getEditor().getDocument().getDefaultRootElement();
    //      return root.getElementIndex( getCursorPosition());
    //   }
    public void toggleBookmarkCurrentLine() {

        Element root = getEditor().getDocument().getDefaultRootElement();
        toggleBookmark(root.getElementIndex(getCursorPosition()));
    }

    public void toggleBookmark(int line) {

        Bookmark bm = getBookmark(line);
        if (bm != null) {
            bookmarks.removeElement(bm);
            parent.removeBookmark(bm);
        } else {
            Element root = getEditor().getDocument().getDefaultRootElement();
            Element element = root.getElement(line);
            bm = new Bookmark(element, document);
            parent.addBookmark(bm);
            bookmarks.addElement(bm);
        }
        updateMargins();
    }

    int previousMarginLines = 0;

    private void updateMargins() {

        if (getLines() != previousMarginLines) {
            if (topEditor.isInitialised()) {
                topEditor.updateMargins();
            }
            bottomEditor.updateMargins();
            if (selectedEditor == topEditor) {
                bottomEditor.getEditor().revalidate();
                bottomEditor.getEditor().repaint();
            } else if (topEditor.isInitialised()) {
                topEditor.getEditor().revalidate();
                topEditor.getEditor().repaint();
            }
        }
    }

    public Bookmark getBookmark(int line) {

        resetBookmarks();
        for (int i = 0; i < bookmarks.size(); i++) {
            Bookmark b = (Bookmark) bookmarks.elementAt(i);
            if (b.getLineNumber() == line) {
                return b;
            }
        }
        return null;
    }

    public boolean hasBookmark(Bookmark bm) {

        for (int i = 0; i < bookmarks.size(); i++) {
            Bookmark b = (Bookmark) bookmarks.elementAt(i);
            if (b.equals(bm)) {
                return true;
            }
        }
        return false;
    }

    public Vector getBookmarks() {

        resetBookmarks();
        return bookmarks;
    }

    public ErrorList getErrors() {

        return errors;
    }

    public void setErrors(ErrorList errorList) {

        this.errors = errorList;
    }

    public void addToErrors(ErrorList errorList) {

        if (this.getErrors() != null) {
            Vector tempErrors = errorList.getErrors();
            if (tempErrors != null) {
                for (int cnt = 0; cnt < tempErrors.size(); ++cnt) {
                    this.errors.addError((XMLError) tempErrors.get(cnt));
                }
            }
        } else {
            this.errors = errorList;
        }
    }

    public XMLError getError(int line) {

        Vector es = errors.getCurrentErrors();
        for (int i = 0; i < es.size(); i++) {
            XMLError error = (XMLError) es.elementAt(i);
            if (error.getLineNumber() == (line + 1)) {
                return error;
            }
        }
        return null;
    }

    public boolean isBookmark(int i) {

        return getBookmark(i) != null;
    }

    // Implementation of CaretListener
    /**
     * Messaged when the caret position has changed.
     */
    public void caretUpdate(CaretEvent e) {

        if ((XmlEditorPane) e.getSource() == getEditor()) {
            hideSelectionPopup();
            caretUpdated = true;
            examiner.reset();
            tagTree = new Vector();
            currentTag = null;
            parentStartTag = null;
            updateMargins();
            updatePositionalStuff();
        }
    }

    public boolean isKeyReleased() {

        return keyReleased;
    }

    private void updatePositionalStuff() {

        if (getEditor().hasFocus()) {
            if (caretUpdated && keyReleased) {
                updateHelper();
                caretUpdated = false;
            } else {
                updatePosition();
            }
        }
    }

    // Extension of BasicTextUI.BasicCaret
    //   private class XmlCaret extends BasicTextUI.BasicCaret {
    public class XmlCaret extends DefaultCaret implements UIResource {

        boolean focus = false;

        public XmlCaret() {

            setBlinkRate(500);
        }

        protected void adjustVisibility(Rectangle nloc) {

            JTextComponent component = getComponent();
            if (component.hasFocus()) {
                super.adjustVisibility(nloc);
            }
        }

        // Always leave the selection highlighted
        public void setSelectionVisible(boolean whatever) {

            super.setSelectionVisible(true);
        }

        // Always leave the caret visible
        public boolean isVisible() {

            boolean result = true;
            if (focus) {
                result = super.isVisible();
            }
            return result;
        }

        public void focusGained(FocusEvent e) {

            focus = true;
            super.focusGained(e);
        }

        public void focusLost(FocusEvent e) {

            focus = false;
        }
    }

    protected void removeAllListeners() {

        // Guaranteed to return a non-null array
        Object[] list = listenerList.getListenerList();
        for (int i = list.length - 2; i >= 0; i -= 2) {
            listenerList.remove((Class) list[i], (EventListener) list[i + 1]);
        }
    }

    public void cleanup() {

        removeAllListeners();
        removeAll();
        if (topEditor != null) {
            topEditor.cleanup();
        }
        if (bottomEditor != null) {
            bottomEditor.cleanup();
        }
        popup.removeAll();
        finalize();
    }

    protected void finalize() {

        selectedEditor = null;
        popupListener = null;
        pattern = null;
        properties = null;
        parent = null;
        popup = null;
        selectionPopup = null;
        // document is cleanedup somewhere else
        document = null;
        topEditor = null;
        bottomEditor = null;
        selectedEditor = null;
        elementNames = null;
        attributeNames = null;
        entityNames = null;
    }

    class WrapperAction extends AbstractAction {

        Action action = null;

        public WrapperAction(Action action, String name) {

            super(name);
            putValue(SMALL_ICON, action.getValue(SMALL_ICON));
            putValue(ACCELERATOR_KEY, action.getValue(ACCELERATOR_KEY));
            putValue(SHORT_DESCRIPTION, action.getValue(SHORT_DESCRIPTION));
            this.action = action;
        }

        public void actionPerformed(ActionEvent e) {

            action.actionPerformed(e);
        }
    }

    class FragmentAction extends AbstractAction {

        private FragmentProperties fragment = null;

        public FragmentAction(FragmentProperties fragment) {

            super(fragment.getName());
            this.fragment = fragment;
            setIcon();
            String keySequence = fragment.getKey();
            if (keySequence != null) {
                int index = keySequence.lastIndexOf("+");
                String mask = null;
                String value = null;
                if (index != -1) {
                    mask = keySequence.substring(0, index);
                    value = keySequence.substring(index + 1, keySequence.length());
                } else {
                    value = keySequence;
                }
                putValue(ACCELERATOR_KEY, props.getKeyPreferences().getKeyStroke(new Keystroke(mask, value)));
            }
            putValue(SHORT_DESCRIPTION, fragment.getName() + " (" + keySequence + ")");
        }

        private void setIcon() {

            ImageIcon icon = null;
            try {
                icon = XngrImageLoader.get().getImage(new URL(fragment.getIcon()));
                if (icon.getIconHeight() != 16 || icon.getIconWidth() != 16) {
                    icon = new ImageIcon(icon.getImage().getScaledInstance(16, 16, Image.SCALE_SMOOTH));
                }
            } catch (Exception e) {
                icon = null;
            }
            if (icon == null) {
                icon = XngrImageLoader.get().getImage("com/cladonia/xngreditor/icons/DefaultFragmentIcon.gif");
            }
            putValue(SMALL_ICON, icon);
        }

        public void actionPerformed(ActionEvent e) {

            insertFragment(fragment.isBlock(), fragment.getContent());
            setFocus();
        }
    }

    public synchronized Tag getCurrentTag() {

        if (currentTag == null) {
            currentTag = ((XmlDocument) getEditor().getDocument()).getCurrentTag(getCursorPosition());
        }
        return currentTag;
    }

    public synchronized Tag getParentStartTag() {

        if (parentStartTag == null) {
            parentStartTag = ((XmlDocument) getEditor().getDocument()).getParentStartTag(getCursorPosition());
        }
        return parentStartTag;
    }

    public synchronized Tag getParentStartTag(Tag child) {

        if (child != null) {
            if (tagTree != null) {
                int index = tagTree.indexOf(child);
                if (index != -1) {
                    if (tagTree.size() > index + 1) {
                        return (Tag) tagTree.elementAt(index + 1);
                    } else {
                        Tag tag = ((XmlDocument) getEditor().getDocument()).getParentStartTag(child.getStart());
                        tagTree.addElement(tag);
                        return tag;
                    }
                }
            }
            return ((XmlDocument) getEditor().getDocument()).getParentStartTag(child.getStart());
        } else {
            return null;
        }
    }

    private synchronized Tag getCurrentStartTag() {

        if (tagTree.size() == 0) {
            Tag tag = selectedEditor.getCurrentStartTag();
            if (tag == null) {
                return null;
            }
            tagTree.addElement(tag);
        }
        return (Tag) tagTree.elementAt(0);
    }

    private class Examiner extends Thread {

        boolean reset = false;
        private Vector elementListeners = null;
        private Vector currentElementsListeners = null;
        private Vector currentSiblingsListeners = null;
        private Vector currentElementListeners = null;
        private Vector currentAttributesListeners = null;
        private Vector attributeListeners = null;
        private Vector valueListeners = null;
        private ElementInformation current = null;
        private Vector currentSiblings = null;
        private Vector currentElements = null;
        private Vector currentAttributes = null;
        private Vector elements = null;
        private Vector attributes = null;
        private Vector values = null;

        public synchronized void reset() {

            currentElements = null;
            currentSiblings = null;
            currentAttributes = null;
            elements = null;
            attributes = null;
            values = null;
            current = null;
            reset = true;
        }

        public synchronized void getCurrentSiblings(CurrentSiblingsListener listener) {

            if (currentSiblings != null) {
                listener.setCurrentSiblings(currentSiblings);
            } else {
                if (currentSiblingsListeners != null && !currentSiblingsListeners.contains(listener)) {
                    currentSiblingsListeners.addElement(listener);
                } else {
                    currentSiblingsListeners = new Vector();
                    currentSiblingsListeners.addElement(listener);
                }
            }
        }

        public synchronized void getCurrentElements(CurrentElementsListener listener) {

            if (currentElements != null) {
                listener.setCurrentElements(currentElements);
            } else {
                if (currentElementsListeners != null && !currentElementsListeners.contains(listener)) {
                    currentElementsListeners.addElement(listener);
                } else {
                    currentElementsListeners = new Vector();
                    currentElementsListeners.addElement(listener);
                }
            }
        }

        public synchronized void getCurrentAttributes(CurrentAttributesListener listener) {

            if (currentAttributes != null) {
                listener.setCurrentAttributes(currentAttributes);
            } else {
                if (currentAttributesListeners != null && !currentAttributesListeners.contains(listener)) {
                    currentAttributesListeners.addElement(listener);
                } else {
                    currentAttributesListeners = new Vector();
                    currentAttributesListeners.addElement(listener);
                }
            }
        }

        public synchronized void getCurrentElement(CurrentElementListener listener) {

            if (current != null) {
                listener.setCurrentElement(current);
            } else {
                if (currentElementListeners != null && !currentElementListeners.contains(listener)) {
                    currentElementListeners.addElement(listener);
                } else {
                    currentElementListeners = new Vector();
                    currentElementListeners.addElement(listener);
                }
            }
        }

        public synchronized void getElements(ElementsListener listener) {

            if (elements != null) {
                listener.setElements(elements);
            } else {
                if (elementListeners != null && !elementListeners.contains(listener)) {
                    elementListeners.addElement(listener);
                } else {
                    elementListeners = new Vector();
                    elementListeners.addElement(listener);
                }
            }
        }

        public synchronized void getAttributes(AttributesListener listener) {

            if (attributes != null) {
                listener.setAttributes(attributes);
            } else {
                if (attributeListeners != null && !attributeListeners.contains(listener)) {
                    attributeListeners.addElement(listener);
                } else {
                    attributeListeners = new Vector();
                    attributeListeners.addElement(listener);
                }
            }
        }

        public synchronized void getValues(ValuesListener listener) {

            if (values != null) {
                listener.setValues(values);
            } else {
                if (valueListeners != null && !valueListeners.contains(listener)) {
                    valueListeners.addElement(listener);
                } else {
                    valueListeners = new Vector();
                    valueListeners.addElement(listener);
                }
            }
        }

        public boolean isReset() {

            return reset;
        }

        // always running
        public void run() {

            while (true) {
                try {
                    reset = false;
                    if (valueListeners != null && valueListeners.size() > 0) {
                        values = getCurrentAttributeValues();
                        if (!reset) {
                            for (int i = 0; i < valueListeners.size(); i++) {
                                ((ValuesListener) valueListeners.elementAt(i)).setValues(values);
                            }
                            valueListeners.removeAllElements();
                        }
                    } else if (attributeListeners != null && attributeListeners.size() > 0) {
                        attributes = Editor.this.getAttributes();
                        if (!reset) {
                            for (int i = 0; i < attributeListeners.size(); i++) {
                                ((AttributesListener) attributeListeners.elementAt(i)).setAttributes(attributes);
                            }
                            attributeListeners.removeAllElements();
                        }
                    } else if (elementListeners != null && elementListeners.size() > 0) {
                        elements = getChildElements();
                        if (!reset) {
                            for (int i = 0; i < elementListeners.size(); i++) {
                                ((ElementsListener) elementListeners.elementAt(i)).setElements(elements);
                            }
                            elementListeners.removeAllElements();
                        }
                    } else if (currentElementsListeners != null && currentElementsListeners.size() > 0) {
                        currentElements = getCurrentChildElements();
                        if (!reset) {
                            for (int i = 0; i < currentElementsListeners.size(); i++) {
                                ((CurrentElementsListener) currentElementsListeners.elementAt(i))
                                        .setCurrentElements(currentElements);
                            }
                            currentElementsListeners.removeAllElements();
                        }
                    } else if (currentSiblingsListeners != null && currentSiblingsListeners.size() > 0) {
                        currentSiblings = Editor.this.getCurrentSiblings();
                        if (!reset) {
                            for (int i = 0; i < currentSiblingsListeners.size(); i++) {
                                ((CurrentSiblingsListener) currentSiblingsListeners.elementAt(i))
                                        .setCurrentSiblings(currentSiblings);
                            }
                            currentSiblingsListeners.removeAllElements();
                        }
                    } else if (currentElementListeners != null && currentElementListeners.size() > 0) {
                        current = Editor.this.getCurrentElement();
                        if (!reset) {
                            for (int i = 0; i < currentElementListeners.size(); i++) {
                                ((CurrentElementListener) currentElementListeners.elementAt(i))
                                        .setCurrentElement(current);
                            }
                            currentElementListeners.removeAllElements();
                        }
                    } else if (currentAttributesListeners != null && currentAttributesListeners.size() > 0) {
                        currentAttributes = Editor.this.getCurrentAttributes();
                        if (!reset) {
                            for (int i = 0; i < currentAttributesListeners.size(); i++) {
                                ((CurrentAttributesListener) currentAttributesListeners.elementAt(i))
                                        .setCurrentAttributes(currentAttributes);
                            }
                            currentAttributesListeners.removeAllElements();
                        }
                    } else {
                        sleep(10);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static interface ElementsListener {

        public void setElements(Vector elements);
    }

    public static interface AttributesListener {

        public void setAttributes(Vector attributes);
    }

    public static interface ValuesListener {

        public void setValues(Vector values);
    }

    public static interface CurrentElementListener {

        public void setCurrentElement(ElementInformation element);
    }

    public static interface CurrentSiblingsListener {

        public void setCurrentSiblings(Vector siblings);
    }

    public static interface CurrentElementsListener {

        public void setCurrentElements(Vector elements);
    }

    public static interface CurrentAttributesListener {

        public void setCurrentAttributes(Vector attributes);
    }

    private class ValuesPopupListener implements ValuesListener {

        String prefix = null;

        public void setPrefix(String prefix) {

            this.prefix = prefix;
        }

        public void setValues(Vector values) {

            showAttributeValueSelectionPopup(prefix, values);
        }
    }

    private class AttributesPopupListener implements AttributesListener {

        String prefix = null;
        Tag tag = null;

        public void setTag(Tag tag) {

            this.tag = tag;
        }

        public void setPrefix(String prefix) {

            this.prefix = prefix;
        }

        public void setAttributes(Vector values) {

            showAttributeSelectionPopup(prefix, values, tag);
        }
    }

    private class ElementsPopupListener implements ElementsListener {

        String prefix = null;
        String parent = null;

        public void setParent(String parent) {

            this.parent = parent;
        }

        public void setPrefix(String prefix) {

            this.prefix = prefix;
        }

        public void setElements(Vector values) {

            showElementSelectionPopup(prefix, values, parent);
        }
    }
    //   private class XMLDropTarget extends DropTarget implements UIResource {
    //      private DropTarget parent = null;
    //      
    //      public XMLDropTarget( DropTarget parent) {
    //         this.parent = parent;
    //      }
    //      
    //      public void dragEnter( DropTargetDragEvent e) {
    //         System.out.println( "XMLDropTarget.dragEnter( "+e+")");
    //         parent.dragEnter( e);
    //      }
    //
    //      public void dragExit( DropTargetEvent e) {
    //         System.out.println( "XMLDropTarget.dragExit( "+e+")");
    //         parent.dragExit( e);
    //      }
    //
    //      public void dragOver( DropTargetDragEvent e) {
    //         System.out.println( "XMLDropTarget.dragOver( "+e+")");
    //         parent.dragOver( e);
    //      }
    //
    //      public void drop( DropTargetDropEvent e) {
    //         System.out.println( "XMLDropTarget.drop( "+e+")");
    //         parent.drop( e);
    //      }
    //
    //      public void dropActionChanged( DropTargetDragEvent e) {
    //         System.out.println( "XMLDropTarget.dropActionChanged( "+e+")");
    //         parent.dropActionChanged( e);
    //      }
    //   }
}