590 lines
18 KiB
Java
590 lines
18 KiB
Java
package net.vhati.modmanager.ui;
|
|
|
|
import java.awt.BorderLayout;
|
|
import java.awt.Component;
|
|
import java.awt.Dimension;
|
|
import java.awt.Font;
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionListener;
|
|
import java.awt.event.FocusAdapter;
|
|
import java.awt.event.FocusEvent;
|
|
import java.awt.event.InputEvent;
|
|
import java.awt.event.KeyEvent;
|
|
import java.io.File;
|
|
import java.io.InputStream;
|
|
import java.io.IOException;
|
|
import java.io.StringWriter;
|
|
import java.util.ArrayList;
|
|
import java.util.Enumeration;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import javax.swing.AbstractAction;
|
|
import javax.swing.BorderFactory;
|
|
import javax.swing.Box;
|
|
import javax.swing.BoxLayout;
|
|
import javax.swing.JButton;
|
|
import javax.swing.JComponent;
|
|
import javax.swing.JFrame;
|
|
import javax.swing.JLabel;
|
|
import javax.swing.JPanel;
|
|
import javax.swing.JOptionPane;
|
|
import javax.swing.JScrollPane;
|
|
import javax.swing.JSplitPane;
|
|
import javax.swing.JTabbedPane;
|
|
import javax.swing.JTextArea;
|
|
import javax.swing.JTextField;
|
|
import javax.swing.JTree;
|
|
import javax.swing.KeyStroke;
|
|
import javax.swing.SwingUtilities;
|
|
import javax.swing.event.AncestorEvent;
|
|
import javax.swing.event.AncestorListener;
|
|
import javax.swing.event.CaretEvent;
|
|
import javax.swing.event.CaretListener;
|
|
import javax.swing.event.UndoableEditEvent;
|
|
import javax.swing.event.UndoableEditListener;
|
|
import javax.swing.text.BadLocationException;
|
|
import javax.swing.text.Caret;
|
|
import javax.swing.tree.DefaultMutableTreeNode;
|
|
import javax.swing.tree.DefaultTreeModel;
|
|
import javax.swing.tree.TreePath;
|
|
import javax.swing.undo.CannotRedoException;
|
|
import javax.swing.undo.UndoManager;
|
|
|
|
import net.vhati.ftldat.FTLDat;
|
|
import net.vhati.modmanager.core.ModUtilities;
|
|
import net.vhati.modmanager.core.SloppyXMLOutputProcessor;
|
|
import net.vhati.modmanager.core.XMLPatcher;
|
|
import net.vhati.modmanager.ui.ClipboardMenuMouseListener;
|
|
|
|
import org.jdom2.Document;
|
|
import org.jdom2.JDOMException;
|
|
|
|
|
|
/**
|
|
* A basic text editor to test XML modding.
|
|
*/
|
|
public class ModXMLSandbox extends JFrame implements ActionListener {
|
|
|
|
private UndoManager undoManager = new UndoManager();
|
|
private Document mainDoc = null;
|
|
|
|
private File dataDatFile;
|
|
|
|
private JTabbedPane areasPane;
|
|
private JScrollPane mainScroll;
|
|
private JScrollPane appendScroll;
|
|
private JScrollPane resultScroll;
|
|
private JSplitPane splitPane;
|
|
private JScrollPane messageScroll;
|
|
|
|
private JTextArea mainArea;
|
|
private JTextArea appendArea;
|
|
private JTextArea resultArea;
|
|
private JTextArea messageArea;
|
|
private JTextField findField;
|
|
private JButton openBtn;
|
|
private JButton patchBtn;
|
|
private JLabel statusLbl;
|
|
|
|
|
|
public ModXMLSandbox( File dataDatFile ) {
|
|
super( "Mod XML Sandbox" );
|
|
this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
|
|
|
this.dataDatFile = dataDatFile;
|
|
|
|
Font sandboxFont = new Font( "Monospaced", Font.PLAIN, 13 );
|
|
|
|
mainArea = new JTextArea();
|
|
mainArea.setTabSize( 4 );
|
|
mainArea.setFont( sandboxFont );
|
|
mainArea.setEditable( false );
|
|
mainArea.addMouseListener( new ClipboardMenuMouseListener() );
|
|
mainScroll = new JScrollPane( mainArea );
|
|
|
|
appendArea = new JTextArea();
|
|
appendArea.setTabSize( 4 );
|
|
appendArea.setFont( sandboxFont );
|
|
appendArea.addMouseListener( new ClipboardMenuMouseListener() );
|
|
appendScroll = new JScrollPane( appendArea );
|
|
|
|
resultArea = new JTextArea();
|
|
resultArea.setTabSize( 4 );
|
|
resultArea.setFont( sandboxFont );
|
|
resultArea.setEditable( false );
|
|
resultArea.addMouseListener( new ClipboardMenuMouseListener() );
|
|
resultScroll = new JScrollPane( resultArea );
|
|
|
|
messageArea = new JTextArea();
|
|
messageArea.setLineWrap( true );
|
|
messageArea.setWrapStyleWord( true );
|
|
messageArea.setTabSize( 4 );
|
|
messageArea.setFont( sandboxFont );
|
|
messageArea.setEditable( false );
|
|
messageArea.addMouseListener( new ClipboardMenuMouseListener() );
|
|
messageArea.setText( "This is a scratchpad to tinker with advanced mod syntax.\n1) Open XML from data.dat to fill the 'main' tab. (ctrl-o)\n2) Write some <mod:command> tags in the 'append' tab. (alt-1,2,3)\n3) Click Patch to see what would happen. (ctrl-p)\nUndo is available. (ctrl-z/ctrl-y)" );
|
|
messageScroll = new JScrollPane( messageArea );
|
|
|
|
JPanel ctrlPanel = new JPanel();
|
|
ctrlPanel.setLayout( new BoxLayout( ctrlPanel, BoxLayout.X_AXIS ) );
|
|
|
|
openBtn = new JButton( "Open Main..." );
|
|
openBtn.addActionListener( this );
|
|
ctrlPanel.add( openBtn );
|
|
|
|
ctrlPanel.add( Box.createHorizontalGlue() );
|
|
|
|
findField = new JTextField( "<find: ctrl-f, F3/shift-F3>", 20 );
|
|
findField.setMaximumSize( new Dimension( 60, findField.getPreferredSize().height ) );
|
|
ctrlPanel.add( findField );
|
|
|
|
ctrlPanel.add( Box.createHorizontalGlue() );
|
|
|
|
patchBtn = new JButton( "Patch" );
|
|
patchBtn.addActionListener( this );
|
|
ctrlPanel.add( patchBtn );
|
|
|
|
areasPane = new JTabbedPane( JTabbedPane.BOTTOM );
|
|
areasPane.add( "Main", mainScroll );
|
|
areasPane.add( "Append", appendScroll );
|
|
areasPane.add( "Result", resultScroll );
|
|
|
|
JPanel topPanel = new JPanel( new BorderLayout() );
|
|
topPanel.add( areasPane, BorderLayout.CENTER );
|
|
topPanel.add( ctrlPanel, BorderLayout.SOUTH );
|
|
|
|
splitPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
|
|
splitPane.setTopComponent( topPanel );
|
|
splitPane.setBottomComponent( messageScroll );
|
|
|
|
JPanel statusPanel = new JPanel();
|
|
statusPanel.setLayout( new BoxLayout(statusPanel, BoxLayout.Y_AXIS) );
|
|
statusPanel.setBorder( BorderFactory.createLoweredBevelBorder() );
|
|
statusLbl = new JLabel(" ");
|
|
statusLbl.setBorder( BorderFactory.createEmptyBorder(2, 4, 2, 4) );
|
|
statusLbl.setAlignmentX( Component.LEFT_ALIGNMENT );
|
|
statusPanel.add( statusLbl );
|
|
|
|
JPanel contentPane = new JPanel( new BorderLayout() );
|
|
contentPane.add( splitPane, BorderLayout.CENTER );
|
|
contentPane.add( statusPanel, BorderLayout.SOUTH );
|
|
this.setContentPane( contentPane );
|
|
|
|
findField.addFocusListener(new FocusAdapter() {
|
|
@Override
|
|
public void focusGained( FocusEvent e ) {
|
|
findField.selectAll();
|
|
}
|
|
});
|
|
CaretListener caretListener = new CaretListener() {
|
|
@Override
|
|
public void caretUpdate( CaretEvent e ) {
|
|
JTextArea currentArea = getCurrentArea();
|
|
if ( currentArea == null ) return;
|
|
if ( e.getSource() != currentArea ) return;
|
|
updateCaretStatus();
|
|
}
|
|
};
|
|
mainArea.addCaretListener( caretListener );
|
|
appendArea.addCaretListener( caretListener );
|
|
resultArea.addCaretListener( caretListener );
|
|
|
|
CaretAncestorListener caretAncestorListener = new CaretAncestorListener();
|
|
mainArea.addAncestorListener( caretAncestorListener );
|
|
appendArea.addAncestorListener( caretAncestorListener );
|
|
resultArea.addAncestorListener( caretAncestorListener );
|
|
|
|
appendArea.getDocument().addUndoableEditListener(new UndoableEditListener() {
|
|
@Override
|
|
public void undoableEditHappened(UndoableEditEvent e) {
|
|
undoManager.addEdit( e.getEdit() );
|
|
}
|
|
});
|
|
AbstractAction undoAction = new AbstractAction( "Undo" ) {
|
|
@Override
|
|
public void actionPerformed( ActionEvent e ) {
|
|
try {undoManager.undo();}
|
|
catch ( CannotRedoException f ) {}
|
|
}
|
|
};
|
|
AbstractAction redoAction = new AbstractAction( "Redo" ) {
|
|
@Override
|
|
public void actionPerformed( ActionEvent e ) {
|
|
try {undoManager.redo();}
|
|
catch ( CannotRedoException f ) {}
|
|
}
|
|
};
|
|
|
|
AbstractAction openAction = new AbstractAction( "Open" ) {
|
|
@Override
|
|
public void actionPerformed( ActionEvent e ) {
|
|
open();
|
|
}
|
|
};
|
|
AbstractAction patchAction = new AbstractAction( "Patch" ) {
|
|
@Override
|
|
public void actionPerformed( ActionEvent e ) {
|
|
patch();
|
|
}
|
|
};
|
|
AbstractAction focusFindAction = new AbstractAction( "Focus Find" ) {
|
|
@Override
|
|
public void actionPerformed( ActionEvent e ) {
|
|
findField.requestFocusInWindow();
|
|
}
|
|
};
|
|
AbstractAction findNextAction = new AbstractAction( "Find Next" ) {
|
|
@Override
|
|
public void actionPerformed( ActionEvent e ) {
|
|
findNext();
|
|
}
|
|
};
|
|
AbstractAction findPreviousAction = new AbstractAction( "Find Previous" ) {
|
|
@Override
|
|
public void actionPerformed( ActionEvent e ) {
|
|
findPrevious();
|
|
}
|
|
};
|
|
|
|
KeyStroke undoShortcut = KeyStroke.getKeyStroke( "control Z" );
|
|
appendArea.getInputMap().put( undoShortcut, "undo" );
|
|
appendArea.getActionMap().put( "undo", undoAction );
|
|
KeyStroke redoShortcut = KeyStroke.getKeyStroke( "control Y" );
|
|
appendArea.getInputMap().put( redoShortcut, "redo" );
|
|
appendArea.getActionMap().put( "redo", redoAction );
|
|
|
|
KeyStroke openShortcut = KeyStroke.getKeyStroke( "control O" );
|
|
contentPane.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( openShortcut, "open" );
|
|
contentPane.getActionMap().put( "open", openAction );
|
|
KeyStroke patchShortcut = KeyStroke.getKeyStroke( "control P" );
|
|
contentPane.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( patchShortcut, "patch" );
|
|
contentPane.getActionMap().put( "patch", patchAction );
|
|
KeyStroke focusFindShortcut = KeyStroke.getKeyStroke( "control F" );
|
|
contentPane.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( focusFindShortcut, "focus find" );
|
|
contentPane.getActionMap().put( "focus find", focusFindAction );
|
|
KeyStroke findNextShortcut = KeyStroke.getKeyStroke( "F3" );
|
|
contentPane.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( findNextShortcut, "find next" );
|
|
contentPane.getActionMap().put( "find next", findNextAction );
|
|
KeyStroke findPreviousShortcut = KeyStroke.getKeyStroke( "shift F3" );
|
|
contentPane.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( findPreviousShortcut, "find previous" );
|
|
contentPane.getActionMap().put( "find previous", findPreviousAction );
|
|
|
|
findField.getInputMap().put( KeyStroke.getKeyStroke( "released ENTER" ), "find next" );
|
|
findField.getActionMap().put( "find next", findNextAction );
|
|
|
|
areasPane.setMnemonicAt( 0, KeyEvent.VK_1 );
|
|
areasPane.setMnemonicAt( 1, KeyEvent.VK_2 );
|
|
areasPane.setMnemonicAt( 2, KeyEvent.VK_3 );
|
|
mainArea.addAncestorListener( new FocusAncestorListener( mainArea ) );
|
|
appendArea.addAncestorListener( new FocusAncestorListener( appendArea ) );
|
|
resultArea.addAncestorListener( new FocusAncestorListener( resultArea ) );
|
|
|
|
this.pack();
|
|
}
|
|
|
|
|
|
@Override
|
|
public void setVisible( boolean b ) {
|
|
super.setVisible( b );
|
|
|
|
if ( b ) {
|
|
// Splitpane has to be realized before the divider can be moved.
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
splitPane.setDividerLocation( 0.80d );
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public void actionPerformed( ActionEvent e ) {
|
|
Object source = e.getSource();
|
|
|
|
if ( source == openBtn ) {
|
|
open();
|
|
}
|
|
else if ( source == patchBtn ) {
|
|
patch();
|
|
}
|
|
}
|
|
|
|
|
|
private void open() {
|
|
messageArea.setText( "" );
|
|
|
|
FTLDat.FTLPack dataP = null;
|
|
InputStream is = null;
|
|
try {
|
|
dataP = new FTLDat.FTLPack( dataDatFile, "r" );
|
|
List<String> innerPaths = dataP.list();
|
|
|
|
String innerPath = promptForInnerPath( innerPaths );
|
|
if ( innerPath == null ) return;
|
|
|
|
is = dataP.getInputStream( innerPath );
|
|
String mainText = ModUtilities.decodeText( is, dataDatFile.getName()+":"+innerPath ).text;
|
|
is.close();
|
|
|
|
mainText = mainText.replaceFirst( "<[?]xml [^>]*?[?]>", "" );
|
|
mainText = "<wrapper xmlns:mod='mod' xmlns:mod-append='mod-append' xmlns:mod-overwrite='mod-overwrite'>"+ mainText +"</wrapper>";
|
|
mainDoc = ModUtilities.parseStrictOrSloppyXML( mainText, "Sandbox Main XML" );
|
|
|
|
StringWriter writer = new StringWriter();
|
|
SloppyXMLOutputProcessor.sloppyPrint( mainDoc, writer, null );
|
|
String displayedText = writer.toString().replaceAll( "\r(?!\n)|(?<!\r)\n|\r\n", "\n" ); // sloppyPrint needs normalizing!?
|
|
mainArea.setText( displayedText );
|
|
mainArea.setCaretPosition( 0 );
|
|
areasPane.setSelectedComponent( mainScroll );
|
|
resultArea.setText( "" );
|
|
}
|
|
catch ( IOException f ) {
|
|
messageArea.setText( f.getMessage() );
|
|
messageArea.setCaretPosition( 0 );
|
|
}
|
|
catch ( JDOMException f ) {
|
|
messageArea.setText( f.getMessage() );
|
|
messageArea.setCaretPosition( 0 );
|
|
}
|
|
finally {
|
|
try {if ( is != null ) is.close();}
|
|
catch ( IOException f ) {}
|
|
|
|
try {if ( dataP != null ) dataP.close();}
|
|
catch ( IOException f ) {}
|
|
}
|
|
}
|
|
|
|
|
|
private void patch() {
|
|
if ( mainDoc == null ) return;
|
|
|
|
messageArea.setText( "" );
|
|
|
|
try {
|
|
String appendText = appendArea.getText();
|
|
appendText = appendText.replaceFirst( "<[?]xml [^>]*?[?]>", "" );
|
|
appendText = "<wrapper xmlns:mod='mod' xmlns:mod-append='mod-append' xmlns:mod-overwrite='mod-overwrite'>"+ appendText +"</wrapper>";
|
|
Document appendDoc = ModUtilities.parseStrictOrSloppyXML( appendText, "Sandbox Append XML" );
|
|
|
|
XMLPatcher patcher = new XMLPatcher();
|
|
patcher.setGlobalPanic( false );
|
|
Document resultDoc = patcher.patch( mainDoc, appendDoc );
|
|
|
|
StringWriter writer = new StringWriter();
|
|
SloppyXMLOutputProcessor.sloppyPrint( resultDoc, writer, null );
|
|
String displayedText = writer.toString().replaceAll( "\r(?!\n)|(?<!\r)\n|\r\n", "\n" ); // sloppyPrint needs normalizing!?
|
|
resultArea.setText( displayedText );
|
|
resultArea.setCaretPosition( 0 );
|
|
areasPane.setSelectedComponent( resultScroll );
|
|
}
|
|
catch ( Exception f ) {
|
|
messageArea.setText( f.getMessage() );
|
|
messageArea.setCaretPosition( 0 );
|
|
}
|
|
}
|
|
|
|
|
|
private void findNext() {
|
|
JTextArea currentArea = getCurrentArea();
|
|
if ( currentArea == null ) return;
|
|
|
|
String query = findField.getText();
|
|
if ( query.length() == 0 ) return;
|
|
|
|
Caret caret = currentArea.getCaret();
|
|
int from = Math.max( caret.getDot(), caret.getMark() );
|
|
|
|
Pattern ptn = Pattern.compile( "(?i)"+ Pattern.quote(query) );
|
|
Matcher m = ptn.matcher( currentArea.getText() );
|
|
if ( m.find(from) ) {
|
|
caret.setDot( m.start() );
|
|
caret.moveDot( m.end() );
|
|
caret.setSelectionVisible( true );
|
|
}
|
|
}
|
|
|
|
private void findPrevious() {
|
|
JTextArea currentArea = getCurrentArea();
|
|
if ( currentArea == null ) return;
|
|
|
|
String query = findField.getText();
|
|
if ( query.length() == 0 ) return;
|
|
|
|
Caret caret = currentArea.getCaret();
|
|
int from = Math.min( caret.getDot(), caret.getMark() );
|
|
|
|
Pattern ptn = Pattern.compile( "(?i)"+ Pattern.quote(query) );
|
|
Matcher m = ptn.matcher( currentArea.getText() );
|
|
m.region( 0, from );
|
|
int lastStart = -1;
|
|
int lastEnd = -1;
|
|
while ( m.find() ) {
|
|
lastStart = m.start();
|
|
lastEnd = m.end();
|
|
}
|
|
if ( lastStart != -1 ) {
|
|
caret.setDot( lastStart );
|
|
caret.moveDot( lastEnd );
|
|
caret.setSelectionVisible( true );
|
|
}
|
|
}
|
|
|
|
|
|
private void updateCaretStatus() {
|
|
JTextArea currentArea = getCurrentArea();
|
|
if ( currentArea == null ) return;
|
|
|
|
try {
|
|
int offset = currentArea.getCaretPosition();
|
|
int line = currentArea.getLineOfOffset( offset );
|
|
int lineStart = currentArea.getLineStartOffset( line );
|
|
int col = offset - lineStart;
|
|
int lineCount = currentArea.getLineCount();
|
|
statusLbl.setText( String.format( "Line: %4d/%4d Col: %3d", line+1, lineCount, col+1 ) );
|
|
}
|
|
catch ( BadLocationException e ) {
|
|
statusLbl.setText( String.format( "Line: ???/ ??? Col: ???" ) );
|
|
}
|
|
}
|
|
|
|
|
|
private JTextArea getCurrentArea() {
|
|
if ( areasPane.getSelectedIndex() == 0 )
|
|
return mainArea;
|
|
else if ( areasPane.getSelectedIndex() == 1 )
|
|
return appendArea;
|
|
else if ( areasPane.getSelectedIndex() == 2 )
|
|
return resultArea;
|
|
else
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Shows a modal prompt with a JTree representing a list of paths.
|
|
*
|
|
* @return the selected path, null otherwise
|
|
*/
|
|
private String promptForInnerPath( List<String> innerPaths ) {
|
|
String result = null;
|
|
|
|
Set<String> sortedPaths = new TreeSet<String>( innerPaths );
|
|
for ( Iterator<String> it = sortedPaths.iterator(); it.hasNext(); ) {
|
|
if ( !it.next().endsWith(".xml") ) it.remove();
|
|
}
|
|
|
|
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode( "/" );
|
|
DefaultTreeModel treeModel = new DefaultTreeModel( rootNode );
|
|
|
|
for ( String innerPath : sortedPaths ) {
|
|
buildTreeFromString( treeModel, innerPath );
|
|
}
|
|
|
|
JTree pathTree = new JTree( treeModel );
|
|
pathTree.setRootVisible( false );
|
|
for ( int i=0; i < pathTree.getRowCount(); i++ ) {
|
|
pathTree.expandRow( i );
|
|
}
|
|
JScrollPane treeScroll = new JScrollPane( pathTree );
|
|
treeScroll.setPreferredSize( new Dimension( pathTree.getPreferredSize().width, 300 ) );
|
|
|
|
pathTree.addAncestorListener( new FocusAncestorListener( pathTree ) );
|
|
|
|
int popupResult = JOptionPane.showOptionDialog( this, treeScroll, "Open an XML Resource", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, new String[]{"OK"}, "OK" );
|
|
|
|
if ( popupResult == JOptionPane.OK_OPTION ) {
|
|
StringBuilder buf = new StringBuilder();
|
|
|
|
TreePath selectedPath = pathTree.getSelectionPath();
|
|
if ( selectedPath != null ) {
|
|
for ( Object o : selectedPath.getPath() ) {
|
|
DefaultMutableTreeNode pathComp = (DefaultMutableTreeNode)o;
|
|
if ( !pathComp.isRoot() ) {
|
|
Object userObject = pathComp.getUserObject();
|
|
buf.append( userObject.toString() );
|
|
}
|
|
}
|
|
if ( buf.length() > 0 ) result = buf.toString();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* Adds TreeNodes, if they don't already exist, based on a shash-delimited string.
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
private void buildTreeFromString( DefaultTreeModel treeModel, String path ) {
|
|
DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)treeModel.getRoot();
|
|
DefaultMutableTreeNode currentNode = rootNode;
|
|
|
|
String[] chunks = path.split( "/" );
|
|
|
|
for ( int i=0; i < chunks.length; i++ ) {
|
|
String chunk = chunks[i];
|
|
if ( i < chunks.length-1 )
|
|
chunk += "/";
|
|
|
|
boolean found = false;
|
|
Enumeration<DefaultMutableTreeNode> enumIt = currentNode.children();
|
|
while ( enumIt.hasMoreElements() ) {
|
|
DefaultMutableTreeNode tmpNode = enumIt.nextElement();
|
|
if ( chunk.equals( tmpNode.getUserObject() ) ) {
|
|
found = true;
|
|
currentNode = tmpNode;
|
|
break;
|
|
}
|
|
}
|
|
if ( !found ) {
|
|
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode( chunk );
|
|
currentNode.insert( newNode, currentNode.getChildCount() );
|
|
currentNode = newNode;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private class CaretAncestorListener implements AncestorListener {
|
|
@Override
|
|
public void ancestorAdded( AncestorEvent e ) {
|
|
updateCaretStatus();
|
|
}
|
|
@Override
|
|
public void ancestorMoved( AncestorEvent e ) {
|
|
}
|
|
@Override
|
|
public void ancestorRemoved( AncestorEvent e ) {
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private static class FocusAncestorListener implements AncestorListener {
|
|
private JComponent comp;
|
|
|
|
public FocusAncestorListener( JComponent comp ) {
|
|
this.comp = comp;
|
|
}
|
|
|
|
@Override
|
|
public void ancestorAdded( AncestorEvent e ) {
|
|
comp.requestFocusInWindow();
|
|
}
|
|
@Override
|
|
public void ancestorMoved( AncestorEvent e ) {
|
|
}
|
|
@Override
|
|
public void ancestorRemoved( AncestorEvent e ) {
|
|
}
|
|
}
|
|
}
|