package de.unisiegen.gtitool.ui.style.parser;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.CellEditor;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.LineBorder;
import javax.swing.text.BadLocationException;
import de.unisiegen.gtitool.core.entities.Entity;
import de.unisiegen.gtitool.core.parser.Parseable;
import de.unisiegen.gtitool.core.parser.exceptions.ScannerException;
import de.unisiegen.gtitool.core.parser.style.Style;
import de.unisiegen.gtitool.core.preferences.listener.LanguageChangedListener;
import de.unisiegen.gtitool.core.util.Theme;
import de.unisiegen.gtitool.ui.i18n.Messages;
import de.unisiegen.gtitool.ui.preferences.PreferenceManager;
import de.unisiegen.gtitool.ui.style.document.StyledParserDocument;
import de.unisiegen.gtitool.ui.style.editor.StyledParserEditor;
import de.unisiegen.gtitool.ui.style.listener.ParseableChangedListener;
import de.unisiegen.gtitool.ui.style.sidebar.SideBar;
import de.unisiegen.gtitool.ui.style.sidebar.SideBarListener;
import de.unisiegen.gtitool.ui.utils.Clipboard;
/**
* The styled parser panel class.
*
* @author Christian Fehler
* @version $Id$
* @param <E> The {@link Entity}.
*/
public abstract class StyledParserPanel < E extends Entity < E >> extends
JPanel
{
/**
* The accepted status.
*
* @author Christian Fehler
*/
public enum AcceptedStatus
{
/**
* The none status.
*/
NONE ( Color.BLACK ),
/**
* The accepted status.
*/
ACCEPTED ( Color.GREEN ),
/**
* The not accepted status.
*/
NOT_ACCEPTED ( Color.RED );
/**
* The used {@link Color}.
*/
private Color color;
/**
* Allocates a new {@link AcceptedStatus}.
*
* @param color The {@link Color}.
*/
private AcceptedStatus ( Color color )
{
this.color = color;
}
/**
* Returns the color.
*
* @return The color.
* @see #color
*/
public final Color getColor ()
{
return this.color;
}
}
/**
* The history of parsed objects.
*
* @author Christian Fehler
*/
private class History
{
/**
* Flag that indicates if the neex object should be added.
*/
private boolean addNextObject;
/**
* The current index.
*/
private int index;
/**
* The history list.
*/
private ArrayList < E > list;
/**
* Allocates a new {@link History}.
*/
public History ()
{
this.list = new ArrayList < E > ();
this.index = -1;
this.addNextObject = true;
}
/**
* Add a new object.
*
* @param newObject The object to add.
*/
public final void add ( E newObject )
{
if ( this.addNextObject
&& ( ( this.list.size () == 0 ) || !this.list.get (
this.list.size () - 1 ).toString ().equals (
newObject.toString () ) ) )
{
this.list.add ( newObject );
this.index = this.list.size () - 1;
}
this.addNextObject = true;
}
/**
* Returns true if a redo can be performed.
*
* @return True if a redo can be performed.
*/
public final boolean canRedo ()
{
return this.index < this.list.size () - 1;
}
/**
* Returns true if a undo can be performed.
*
* @return True if a undo can be performed.
*/
public final boolean canUndo ()
{
return this.index > 0;
}
/**
* Preforms a redo.
*
* @return The next object.
*/
public final E redo ()
{
this.index++ ;
this.addNextObject = false;
return this.list.get ( this.index );
}
/**
* {@inheritDoc}
*
* @see Object#toString()
*/
@Override
public final String toString ()
{
return "index: " + this.index + ": " + this.list.toString (); //$NON-NLS-1$//$NON-NLS-2$
}
/**
* Preforms a undo.
*
* @return The previous object.
*/
public final E undo ()
{
this.index-- ;
this.addNextObject = false;
return this.list.get ( this.index );
}
}
/**
* The serial version uid.
*/
private static final long serialVersionUID = -1954392510970145068L;
/**
* The error {@link Color}.
*/
private static final Color ERROR_COLOR = Color.RED;
/**
* The normal {@link Color}.
*/
private static final Color NORMAL_COLOR = Color.BLACK;
/**
* Flag that indicates if the {@link SideBar} is visible.
*/
private boolean sideBarVisible;
/**
* Flag that indicates if the panel is copyable.
*/
private boolean copyable;
/**
* Flag that indicates if the panel is editable.
*/
private boolean editable;
/**
* Flag that indicates if the panel is used as a {@link CellEditor}.
*/
private boolean cellEditor = false;
/**
* The {@link StyledParserDocument}.
*/
protected StyledParserDocument < E > document;
/**
* The {@link StyledParserEditor}.
*/
protected StyledParserEditor < E > editor;
/**
* The {@link History}.
*/
private History history;
/**
* The copy {@link JMenuItem}.
*/
protected JMenuItem jMenuItemCopy;
/**
* The cut {@link JMenuItem}.
*/
protected JMenuItem jMenuItemCut;
/**
* The paste {@link JMenuItem}.
*/
protected JMenuItem jMenuItemPaste;
/**
* The redo {@link JMenuItem}.
*/
protected JMenuItem jMenuItemRedo;
/**
* The undo {@link JMenuItem}.
*/
protected JMenuItem jMenuItemUndo;
/**
* The {@link JPopupMenu}.
*/
private JPopupMenu jPopupMenu;
/**
* The {@link JScrollPane}.
*/
protected JScrollPane jScrollPane;
/**
* The {@link ParseableChangedListener} for the other
* {@link StyledParserPanel}.
*/
protected ParseableChangedListener < E > parseableChangedListenerOther;
/**
* The {@link ParseableChangedListener} for this {@link StyledParserPanel}.
*/
protected ParseableChangedListener < E > parseableChangedListenerThis;
/**
* The {@link SideBar}.
*/
private SideBar < E > sideBar;
/**
* The {@link StyledParserPanel}.
*/
protected StyledParserPanel < E > synchronizedStyledParserPanel = null;
/**
* The {@link AcceptedStatus}.
*/
private AcceptedStatus acceptedStatus = AcceptedStatus.NONE;
/**
* Allocates a new {@link StyledParserPanel}.
*
* @param parseable The input {@link Parseable}.
*/
public StyledParserPanel ( Parseable parseable )
{
this.editable = true;
this.copyable = false;
this.sideBarVisible = true;
this.editor = new StyledParserEditor < E > ();
// PopupMenu
this.jPopupMenu = new JPopupMenu ();
// Undo
this.jMenuItemUndo = new JMenuItem ( Messages
.getString ( "MainWindow.Undo" ) ); //$NON-NLS-1$
this.jMenuItemUndo.setMnemonic ( Messages.getString (
"MainWindow.UndoMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
this.jMenuItemUndo.setIcon ( new ImageIcon ( getClass ().getResource (
"/de/unisiegen/gtitool/ui/icon/small/undo.png" ) ) ); //$NON-NLS-1$
this.jMenuItemUndo.setAccelerator ( KeyStroke.getKeyStroke ( KeyEvent.VK_X,
InputEvent.CTRL_MASK ) );
this.jMenuItemUndo.addActionListener ( new ActionListener ()
{
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent event )
{
handleUndo ();
}
} );
this.jPopupMenu.add ( this.jMenuItemUndo );
// Redo
this.jMenuItemRedo = new JMenuItem ( Messages
.getString ( "MainWindow.Redo" ) ); //$NON-NLS-1$
this.jMenuItemRedo.setMnemonic ( Messages.getString (
"MainWindow.RedoMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
this.jMenuItemRedo.setIcon ( new ImageIcon ( getClass ().getResource (
"/de/unisiegen/gtitool/ui/icon/small/redo.png" ) ) ); //$NON-NLS-1$
this.jMenuItemRedo.setAccelerator ( KeyStroke.getKeyStroke ( KeyEvent.VK_X,
InputEvent.CTRL_MASK ) );
this.jMenuItemRedo.addActionListener ( new ActionListener ()
{
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent event )
{
handleRedo ();
}
} );
this.jPopupMenu.add ( this.jMenuItemRedo );
// Separator
this.jPopupMenu.addSeparator ();
// Cut
this.jMenuItemCut = new JMenuItem ( Messages.getString ( "MainWindow.Cut" ) ); //$NON-NLS-1$
this.jMenuItemCut.setMnemonic ( Messages.getString (
"MainWindow.CutMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
this.jMenuItemCut.setIcon ( new ImageIcon ( getClass ().getResource (
"/de/unisiegen/gtitool/ui/icon/small/cut.png" ) ) ); //$NON-NLS-1$
this.jMenuItemCut.setAccelerator ( KeyStroke.getKeyStroke ( KeyEvent.VK_X,
InputEvent.CTRL_MASK ) );
this.jMenuItemCut.addActionListener ( new ActionListener ()
{
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent event )
{
try
{
Clipboard.getInstance ().copy (
StyledParserPanel.this.editor.getSelectedText () );
StyledParserPanel.this.document
.remove (
StyledParserPanel.this.editor.getSelectionStart (),
( StyledParserPanel.this.editor.getSelectionEnd () - StyledParserPanel.this.editor
.getSelectionStart () ) );
}
catch ( BadLocationException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
}
} );
this.jPopupMenu.add ( this.jMenuItemCut );
// Copy
this.jMenuItemCopy = new JMenuItem ( Messages
.getString ( "MainWindow.Copy" ) ); //$NON-NLS-1$
this.jMenuItemCopy.setMnemonic ( Messages.getString (
"MainWindow.CopyMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
this.jMenuItemCopy.setIcon ( new ImageIcon ( getClass ().getResource (
"/de/unisiegen/gtitool/ui/icon/small/copy.png" ) ) ); //$NON-NLS-1$
this.jMenuItemCopy.setAccelerator ( KeyStroke.getKeyStroke ( KeyEvent.VK_C,
InputEvent.CTRL_MASK ) );
this.jMenuItemCopy.addActionListener ( new ActionListener ()
{
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent event )
{
Clipboard.getInstance ().copy (
StyledParserPanel.this.editor.getSelectedText () );
}
} );
this.jPopupMenu.add ( this.jMenuItemCopy );
// Paste
this.jMenuItemPaste = new JMenuItem ( Messages
.getString ( "MainWindow.Paste" ) ); //$NON-NLS-1$
this.jMenuItemPaste.setMnemonic ( Messages.getString (
"MainWindow.PasteMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
this.jMenuItemPaste.setIcon ( new ImageIcon ( getClass ().getResource (
"/de/unisiegen/gtitool/ui/icon/small/paste.png" ) ) ); //$NON-NLS-1$
this.jMenuItemPaste.setAccelerator ( KeyStroke.getKeyStroke (
KeyEvent.VK_V, InputEvent.CTRL_MASK ) );
this.jMenuItemPaste.addActionListener ( new ActionListener ()
{
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent event )
{
StyledParserPanel.this.editor.replaceSelection ( Clipboard
.getInstance ().paste () );
}
} );
this.jPopupMenu.add ( this.jMenuItemPaste );
// LanguageChangedListener
PreferenceManager.getInstance ().addLanguageChangedListener (
new LanguageChangedListener ()
{
public void languageChanged ()
{
StyledParserPanel.this.jMenuItemUndo.setText ( Messages
.getString ( "MainWindow.Undo" ) ); //$NON-NLS-1$
StyledParserPanel.this.jMenuItemUndo.setMnemonic ( Messages
.getString ( "MainWindow.UndoMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
StyledParserPanel.this.jMenuItemRedo.setText ( Messages
.getString ( "MainWindow.Redo" ) ); //$NON-NLS-1$
StyledParserPanel.this.jMenuItemRedo.setMnemonic ( Messages
.getString ( "MainWindow.RedoMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
StyledParserPanel.this.jMenuItemCut.setText ( Messages
.getString ( "MainWindow.Cut" ) ); //$NON-NLS-1$
StyledParserPanel.this.jMenuItemCut.setMnemonic ( Messages
.getString ( "MainWindow.CutMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
StyledParserPanel.this.jMenuItemCopy.setText ( Messages
.getString ( "MainWindow.Copy" ) ); //$NON-NLS-1$
StyledParserPanel.this.jMenuItemCopy.setMnemonic ( Messages
.getString ( "MainWindow.CopyMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
StyledParserPanel.this.jMenuItemPaste.setText ( Messages
.getString ( "MainWindow.Paste" ) ); //$NON-NLS-1$
StyledParserPanel.this.jMenuItemPaste.setMnemonic ( Messages
.getString ( "MainWindow.PasteMnemonic" ).charAt ( 0 ) ); //$NON-NLS-1$
}
} );
// Editor
this.editor.addMouseListener ( new MouseAdapter ()
{
@Override
public void mousePressed ( MouseEvent event )
{
if ( event.isPopupTrigger () )
{
showPopupMenu ( event );
}
}
@Override
public void mouseReleased ( MouseEvent event )
{
if ( event.isPopupTrigger () )
{
showPopupMenu ( event );
}
}
} );
// Document
this.document = new StyledParserDocument < E > ( parseable );
this.document
.addParseableChangedListener ( new ParseableChangedListener < E > ()
{
public void parseableChanged ( E newObject )
{
fireParseableChanged ( newObject );
}
} );
setLayout ( new BorderLayout () );
this.jScrollPane = new JScrollPane ();
this.jScrollPane.setBorder ( new LineBorder ( NORMAL_COLOR ) );
add ( this.jScrollPane, BorderLayout.CENTER );
this.sideBar = new SideBar < E > ( this.jScrollPane, this.document,
this.editor );
this.sideBar.addSideBarListener ( new SideBarListener ()
{
/**
* Inserts a given text at the given index.
*
* @param index The index in the text, where the text should be inserted.
* @param insertText The text which should be inserted.
*/
public void insertText ( int index, String insertText )
{
int countSpaces = 0;
try
{
while ( StyledParserPanel.this.document.getText (
index + countSpaces, 1 ).equals ( " " ) ) //$NON-NLS-1$
{
countSpaces++ ;
}
}
catch ( BadLocationException e )
{
// Do nothing
}
try
{
int offset = 0;
String text = insertText;
if ( ( countSpaces >= 1 )
&& ( text.substring ( 0, 1 ).equals ( " " ) ) ) //$NON-NLS-1$
{
text = text.substring ( 1 );
offset++ ;
countSpaces-- ;
}
if ( ( countSpaces >= 1 )
&& ( text.substring ( text.length () - 1 ).equals ( " " ) ) ) //$NON-NLS-1$
{
text = text.substring ( 0, text.length () - 1 );
}
StyledParserPanel.this.document.insertString ( index + offset, text,
null );
}
catch ( BadLocationException e )
{
// Do nothing
}
}
/**
* Marks the text with the given offsets.
*
* @param left The left offset of the text which should be marked.
* @param right The right offset of the text which should be marked.
*/
public void markText ( int left, int right )
{
if ( ( StyledParserPanel.this.editor.getSelectionStart () == left )
&& ( StyledParserPanel.this.editor.getSelectionEnd () == right ) )
{
StyledParserPanel.this.removeSelectedText ();
}
else
{
StyledParserPanel.this.selectErrorText ( left, right );
}
}
} );
add ( this.sideBar, BorderLayout.WEST );
this.jScrollPane.setViewportView ( this.editor );
this.editor.setDocument ( this.document );
this.editor.setAutoscrolls ( false );
this.history = new History ();
this.editor.registerKeyboardAction ( new ActionListener ()
{
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent event )
{
handleUndo ();
}
}, KeyStroke.getKeyStroke ( KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK ),
JComponent.WHEN_FOCUSED );
this.editor.registerKeyboardAction ( new ActionListener ()
{
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent event )
{
handleRedo ();
}
}, KeyStroke.getKeyStroke ( KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK ),
JComponent.WHEN_FOCUSED );
}
/**
* {@inheritDoc}
*
* @see Component#addFocusListener(FocusListener)
*/
@Override
public final void addFocusListener ( FocusListener listener )
{
this.editor.addFocusListener ( listener );
}
/**
* {@inheritDoc}
*
* @see Component#addKeyListener(KeyListener)
*/
@Override
public final void addKeyListener ( KeyListener listener )
{
this.editor.addKeyListener ( listener );
}
/**
* {@inheritDoc}
*
* @see Component#addMouseListener(java.awt.event.MouseListener)
*/
@Override
public synchronized void addMouseListener ( MouseListener l )
{
this.editor.addMouseListener ( l );
this.sideBar.addMouseListener ( l );
super.addMouseListener ( l );
}
/**
* Returns the sideBar.
*
* @return The sideBar.
* @see #sideBar
*/
public SideBar < E > getSideBar ()
{
return this.sideBar;
}
/**
* Returns the editor.
*
* @return The editor.
* @see #editor
*/
public StyledParserEditor < E > getEditor ()
{
return this.editor;
}
/**
* Adds the given style.
*
* @param token The token.
* @param style The {@link Style}.
*/
protected final void addOverwrittenStyle ( String token, Style style )
{
this.document.addOverwrittenStyle ( token, style );
}
/**
* Adds the given {@link ParseableChangedListener}.
*
* @param listener The {@link ParseableChangedListener}.
*/
public final void addParseableChangedListener (
ParseableChangedListener < E > listener )
{
this.listenerList.add ( ParseableChangedListener.class, listener );
}
/**
* Returns the document.
*
* @return The document.
* @see #document
*/
public StyledParserDocument < E > getDocument ()
{
return this.document;
}
/**
* Checks the given parsed {@link Object}.
*
* @param parsedObject The parsed {@link Object} to check.
* @return The input parsed {@link Object} or null, if the parsed
* {@link Object} is not correct.
*/
protected abstract E checkParsedObject ( E parsedObject );
/**
* Clears the overwritten {@link Style}.
*
* @param style The {@link Style} to clear.
*/
protected final void clearOverwrittenStyle ( Style style )
{
this.document.clearOverwrittenStyle ( style );
}
/**
* Let the listeners know that the {@link Object} has changed.
*
* @param newObject The new {@link Object}.
*/
@SuppressWarnings ( "unchecked" )
public final void fireParseableChanged ( E newObject )
{
E checkedObject = checkParsedObject ( newObject );
setErrorIndicator ( checkedObject == null );
// History
if ( checkedObject != null )
{
this.history.add ( checkedObject );
}
ParseableChangedListener [] listeners = this.listenerList
.getListeners ( ParseableChangedListener.class );
for ( ParseableChangedListener < E > current : listeners )
{
current.parseableChanged ( checkedObject );
}
}
/**
* Returns the {@link JPopupMenu}.
*
* @return The {@link JPopupMenu}.
* @see #jPopupMenu
*/
public final JPopupMenu getJPopupMenu ()
{
return this.jPopupMenu;
}
/**
* Returns the {@link Object} for the program text within the document. Throws
* an exception if a parsing error occurred.
*
* @return The {@link Object} for the program text.
*/
public final E getParsedObject ()
{
return checkParsedObject ( this.document.getParsedObject () );
}
/**
* Returns the text contained in the editor.
*
* @return The text contained in the editor.
*/
public final String getText ()
{
return this.editor.getText ();
}
/**
* Handles the redo action.
*/
protected final void handleRedo ()
{
if ( this.history.canRedo () )
{
this.editor.setText ( this.history.redo ().toString () );
}
}
/**
* Handles the undo action.
*/
protected final void handleUndo ()
{
if ( this.history.canUndo () )
{
this.editor.setText ( this.history.undo ().toString () );
}
}
/**
* Returns true if this {@link StyledParserPanel} is used as a
* {@link CellEditor}, otherwise false.
*
* @return True if this {@link StyledParserPanel} is used as a
* {@link CellEditor}, otherwise false.
*/
public boolean isCellEditor ()
{
return this.cellEditor;
}
/**
* Return the copyable value.
*
* @return The copyable value.
*/
public final boolean isCopyable ()
{
return this.copyable;
}
/**
* Return the editable value.
*
* @return The editable value.
*/
public final boolean isEditable ()
{
return this.editable;
}
/**
* Return the enabled value.
*
* @return The enabled value.
*/
@Override
public final boolean isEnabled ()
{
return super.isEnabled ();
}
/**
* Returns the right alignment value.
*
* @return The right alignment value.
*/
public final boolean isRightAlignment ()
{
return this.document.isRightAlignment ();
}
/**
* Return the sideBarVisible value.
*
* @return The sideBarVisible value.
*/
public final boolean isSideBarVisible ()
{
return this.sideBarVisible;
}
/**
* Parses the document and returns the parsed object or null, if the text
* could not be parsed.
*
* @return The parsed object or null, if the text could not be parsed.
*/
public final E parse ()
{
E checkedObject = checkParsedObject ( this.document.parse () );
setErrorIndicator ( checkedObject == null );
return checkedObject;
}
/**
* {@inheritDoc}
*
* @see Component#removeFocusListener(FocusListener)
*/
@Override
public final void removeFocusListener ( FocusListener listener )
{
this.editor.removeFocusListener ( listener );
}
/**
* {@inheritDoc}
*
* @see Component#removeKeyListener(KeyListener)
*/
@Override
public final void removeKeyListener ( KeyListener listener )
{
this.editor.removeKeyListener ( listener );
}
/**
* Removes the given {@link ParseableChangedListener}.
*
* @param listener The {@link ParseableChangedListener}.
*/
public final void removeParseableChangedListener (
ParseableChangedListener < E > listener )
{
this.listenerList.remove ( ParseableChangedListener.class, listener );
}
/**
* Removes the selectedText.
*/
protected final void removeSelectedText ()
{
int start = this.editor.getSelectionStart ();
int end = this.editor.getSelectionEnd ();
try
{
if ( start < end )
{
this.document.remove ( start, ( end - start ) );
}
else
{
this.document.remove ( end, ( start - end ) );
}
}
catch ( BadLocationException e )
{
e.printStackTrace ();
}
}
/**
* {@inheritDoc}
*
* @see JComponent#requestFocus()
*/
@Override
public final void requestFocus ()
{
this.editor.requestFocus ();
}
/**
* Selects the error text.
*
* @param left The left index.
* @param right The right index.
*/
protected final void selectErrorText ( int left, int right )
{
this.editor.select ( left, right );
}
/**
* Sets the {@link AcceptedStatus}.
*
* @param acceptedStatus The {@link AcceptedStatus} to set.
*/
public final void setAcceptedStatus ( AcceptedStatus acceptedStatus )
{
this.acceptedStatus = acceptedStatus;
setErrorIndicator ( false );
}
/**
* Sets the cell editor flag.
*
* @param cellEditor The cell editor flag.
*/
public final void setCellEditor ( boolean cellEditor )
{
this.cellEditor = cellEditor;
if ( this.cellEditor )
{
this.jScrollPane
.setHorizontalScrollBarPolicy ( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
this.jScrollPane
.setVerticalScrollBarPolicy ( ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER );
this.editor.setCellEditor ( true );
setSideBarVisible ( false );
}
else
{
this.jScrollPane
.setHorizontalScrollBarPolicy ( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED );
this.jScrollPane
.setVerticalScrollBarPolicy ( ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED );
this.editor.setCellEditor ( false );
}
}
/**
* Sets the specified boolean to indicate whether or not this
* {@link StyledParserPanel} should be copyable.
*
* @param copyable The boolean to be set.
*/
public final void setCopyable ( boolean copyable )
{
this.copyable = copyable;
setStatus ();
}
/**
* Sets the specified boolean to indicate whether or not this
* {@link StyledParserPanel} should be editable.
*
* @param editable The boolean to be set.
*/
public final void setEditable ( boolean editable )
{
this.editable = editable;
setStatus ();
}
/**
* Sets the specified boolean to indicate whether or not this
* {@link StyledParserPanel} should be enabled.
*
* @param enabled The boolean to be set.
*/
@Override
public final void setEnabled ( boolean enabled )
{
this.sideBar.setEnabled ( enabled );
this.editor.setEnabled ( enabled );
if ( enabled )
{
this.editor.setBackground ( Color.WHITE );
}
else
{
this.editor.setBackground ( Theme.DISABLED_COMPONENT_COLOR );
}
super.setEnabled ( enabled );
}
/**
* Sets the error indicator of this {@link StyledParserPanel}.
*
* @param error Flag that indicates if there is an error.
*/
private final void setErrorIndicator ( boolean error )
{
if ( this.acceptedStatus.equals ( AcceptedStatus.NONE ) )
{
if ( ( this.document.getParsedObject () == null ) || error )
{
this.jScrollPane.setBorder ( new LineBorder ( ERROR_COLOR ) );
}
else
{
this.jScrollPane.setBorder ( new LineBorder ( NORMAL_COLOR ) );
}
}
else if ( this.acceptedStatus.equals ( AcceptedStatus.ACCEPTED ) )
{
this.jScrollPane.setBorder ( new LineBorder ( AcceptedStatus.ACCEPTED
.getColor () ) );
}
else if ( this.acceptedStatus.equals ( AcceptedStatus.NOT_ACCEPTED ) )
{
this.jScrollPane.setBorder ( new LineBorder ( AcceptedStatus.NOT_ACCEPTED
.getColor () ) );
}
else
{
throw new RuntimeException ( "unsupported accepted status" ); //$NON-NLS-1$
}
}
/**
* Sets the extern {@link ScannerException}s.
*
* @param exceptions The {@link ScannerException}s to set.
*/
protected final void setException ( Iterable < ScannerException > exceptions )
{
this.document.setException ( exceptions );
setErrorIndicator ( exceptions.iterator ().hasNext () );
}
/**
* Sets the {@link Entity}s which should be highlighted.
*
* @param entities The {@link Entity}s which should be highlighted.
*/
public final void setHighlightedParseableEntity ( Entity < ? > ... entities )
{
this.document.setHighlightedParseableEntity ( entities );
}
/**
* Sets the {@link Entity} which should be highlighted.
*
* @param entity The {@link Entity} which should be highlighted.
*/
public final void setHighlightedParseableEntity ( Entity < ? > entity )
{
this.document.setHighlightedParseableEntity ( entity );
}
/**
* Sets the {@linkEntity}s which should be highlighted.
*
* @param entities The {@link Entity}s which should be highlighted.
*/
public final void setHighlightedParseableEntity (
Iterable < ? extends Entity < ? > > entities )
{
this.document.setHighlightedParseableEntity ( entities );
}
/**
* Sets the right alignment.
*
* @param rightAlignment The right alignment to set.
*/
public final void setRightAlignment ( boolean rightAlignment )
{
this.document.setRightAlignment ( rightAlignment );
}
/**
* Sets the specified boolean to indicate whether or not the {@link SideBar}
* should be visible.
*
* @param sideBarVisible The boolean to be set.
*/
public final void setSideBarVisible ( boolean sideBarVisible )
{
if ( sideBarVisible )
{
if ( !this.cellEditor )
{
this.sideBarVisible = true;
setStatus ();
}
}
else
{
this.sideBarVisible = false;
setStatus ();
}
}
/**
* Sets the status.
*/
private final void setStatus ()
{
this.editor.setEditable ( this.editable );
if ( this.editable )
{
this.editor.setFocusable ( true );
}
else
{
if ( this.copyable )
{
this.editor.setFocusable ( true );
this.editor.setCursor ( new Cursor ( Cursor.TEXT_CURSOR ) );
}
else
{
this.editor.setFocusable ( false );
this.editor.setCursor ( new Cursor ( Cursor.DEFAULT_CURSOR ) );
}
}
// SideBar
this.sideBar.setVisible ( this.sideBarVisible );
}
/**
* Sets the {@link Object} of the {@link StyledParserPanel}.
*
* @param object The input {@link Object}.
*/
public final void setText ( Object object )
{
if ( object == null )
{
this.editor.setText ( "" ); //$NON-NLS-1$
}
else
{
this.editor.setText ( object.toString () );
}
}
/**
* Shows the {@link JPopupMenu} and enables the copy and cut menu item if text
* is selected, otherwise they are diasabled.
*
* @param event
*/
protected final void showPopupMenu ( MouseEvent event )
{
if ( !isEnabled () )
{
return;
}
if ( this.editable )
{
int start = this.editor.getSelectionStart ();
int end = this.editor.getSelectionEnd ();
this.jMenuItemUndo.setEnabled ( this.history.canUndo () );
this.jMenuItemRedo.setEnabled ( this.history.canRedo () );
this.jMenuItemCopy.setEnabled ( start != end );
this.jMenuItemCut.setEnabled ( start != end );
this.jMenuItemPaste.setEnabled ( true );
this.jPopupMenu.show ( event.getComponent (), event.getX (), event
.getY () );
}
else if ( this.copyable )
{
int start = this.editor.getSelectionStart ();
int end = this.editor.getSelectionEnd ();
this.jMenuItemUndo.setEnabled ( false );
this.jMenuItemRedo.setEnabled ( false );
this.jMenuItemCopy.setEnabled ( start != end );
this.jMenuItemCut.setEnabled ( false );
this.jMenuItemPaste.setEnabled ( false );
this.jPopupMenu.show ( event.getComponent (), event.getX (), event
.getY () );
}
}
/**
* Synchronizes this {@link StyledParserPanel} with the given
* {@link StyledParserPanel}.
*
* @param styledParserPanel The other {@link StyledParserPanel} which should
* be synchronized.
*/
public final void synchronize ( StyledParserPanel < E > styledParserPanel )
{
if ( styledParserPanel == null )
{
this.synchronizedStyledParserPanel
.removeParseableChangedListener ( this.parseableChangedListenerOther );
removeParseableChangedListener ( this.parseableChangedListenerThis );
this.parseableChangedListenerThis = null;
this.parseableChangedListenerOther = null;
this.synchronizedStyledParserPanel = null;
return;
}
this.synchronizedStyledParserPanel = styledParserPanel;
this.editor.setText ( this.synchronizedStyledParserPanel.getText () );
this.parseableChangedListenerOther = new ParseableChangedListener < E > ()
{
public void parseableChanged ( @SuppressWarnings ( "unused" ) E newObject )
{
removeParseableChangedListener ( StyledParserPanel.this.parseableChangedListenerThis );
StyledParserPanel.this.editor
.setText ( StyledParserPanel.this.synchronizedStyledParserPanel
.getText () );
addParseableChangedListener ( StyledParserPanel.this.parseableChangedListenerThis );
}
};
this.parseableChangedListenerThis = new ParseableChangedListener < E > ()
{
public void parseableChanged ( @SuppressWarnings ( "unused" ) E newObject )
{
StyledParserPanel.this.synchronizedStyledParserPanel
.removeParseableChangedListener ( StyledParserPanel.this.parseableChangedListenerOther );
StyledParserPanel.this.synchronizedStyledParserPanel
.setText ( StyledParserPanel.this.editor.getText () );
StyledParserPanel.this.synchronizedStyledParserPanel
.addParseableChangedListener ( StyledParserPanel.this.parseableChangedListenerOther );
}
};
this.synchronizedStyledParserPanel
.addParseableChangedListener ( this.parseableChangedListenerOther );
addParseableChangedListener ( this.parseableChangedListenerThis );
}
}