Package com.eviware.soapui.support.xml

Source Code of com.eviware.soapui.support.xml.JXEditTextArea$UndoAction

/*
*  soapUI, copyright (C) 2004-2011 eviware.com
*
*  soapUI is free software; you can redistribute it and/or modify it under the
*  terms of version 2.1 of the GNU Lesser General Public License as published by
*  the Free Software Foundation.
*
*  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
*  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*  See the GNU Lesser General Public License for more details at gnu.org.
*/

package com.eviware.soapui.support.xml;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JPopupMenu;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.BadLocationException;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;

import org.syntax.jedit.InputHandler;
import org.syntax.jedit.JEditTextArea;
import org.syntax.jedit.SyntaxStyle;
import org.syntax.jedit.tokenmarker.GroovyTokenMarker;
import org.syntax.jedit.tokenmarker.JavaScriptTokenMarker;
import org.syntax.jedit.tokenmarker.TSQLTokenMarker;
import org.syntax.jedit.tokenmarker.Token;
import org.syntax.jedit.tokenmarker.TokenMarker;
import org.syntax.jedit.tokenmarker.XMLTokenMarker;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.model.settings.SettingsListener;
import com.eviware.soapui.settings.UISettings;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.actions.FindAndReplaceDialog;
import com.eviware.soapui.support.actions.FindAndReplaceable;
import com.eviware.soapui.support.components.JEditorStatusBar.JEditorStatusBarTarget;
import com.eviware.soapui.support.xml.actions.FormatXmlAction;
import com.eviware.soapui.support.xml.actions.LoadXmlTextAreaAction;
import com.eviware.soapui.support.xml.actions.SaveXmlTextAreaAction;

/**
* JEditTextArea extension targeted specifically at XML-editing.
*
* //@todo move font handling to subclass
*
* @author Ole.Matzura
*/

public class JXEditTextArea extends JEditTextArea implements UndoableEditListener, FocusListener, FindAndReplaceable,
    JEditorStatusBarTarget
{
  public static final int UNDO_LIMIT = 1500;
  private UndoManager undoManager;
  private UndoAction undoAction;
  private RedoAction redoAction;
  private FindAndReplaceDialog findAndReplaceAction;
  private boolean discardEditsOnSet = true;
  private GoToLineAction goToLineAction;

  public static JXEditTextArea createXmlEditor( boolean addPopup )
  {
    JXEditTextArea editArea = new JXEditTextArea( new XMLTokenMarker() );

    if( addPopup )
    {
      JPopupMenu inputPopup = new JPopupMenu();

      inputPopup.add( new FormatXmlAction( editArea ) );
      inputPopup.addSeparator();
      inputPopup.add( editArea.getUndoAction() );
      inputPopup.add( editArea.getRedoAction() );
      inputPopup.add( editArea.createCopyAction() );
      inputPopup.add( editArea.createCutAction() );
      inputPopup.add( editArea.createPasteAction() );
      inputPopup.addSeparator();
      inputPopup.add( editArea.getFindAndReplaceAction() );
      inputPopup.addSeparator();
      inputPopup.add( editArea.getGoToLineAction() );

      inputPopup.addSeparator();
      inputPopup.add( new SaveXmlTextAreaAction( editArea, "Save Editor Content" ) );
      inputPopup.add( new LoadXmlTextAreaAction( editArea, "Load Editor Content" ) );

      editArea.setRightClickPopup( inputPopup );
    }

    return editArea;
  }

  public static JXEditTextArea createGroovyEditor()
  {
    return new JXEditTextArea( new GroovyTokenMarker() );
  }

  public static JXEditTextArea createJavaScriptEditor()
  {
    return new JXEditTextArea( new JavaScriptTokenMarker() );
  }

  public static JXEditTextArea createSqlEditor()
  {
    return new JXEditTextArea( new TSQLTokenMarker() );
  }

  public JXEditTextArea( TokenMarker tokenMarker )
  {
    getPainter().setFont( UISupport.getEditorFont() );
    getPainter().setLineHighlightColor( new Color( 240, 240, 180 ) );
    getPainter().setStyles( createXmlStyles() );
    setTokenMarker( tokenMarker );
    setBorder( BorderFactory.createEtchedBorder() );
    addFocusListener( this );

    undoAction = new UndoAction();
    getInputHandler().addKeyBinding( "C+Z", undoAction );
    redoAction = new RedoAction();
    getInputHandler().addKeyBinding( "C+Y", redoAction );
    findAndReplaceAction = new FindAndReplaceDialog( this );
    getInputHandler().addKeyBinding( "C+F", findAndReplaceAction );
    getInputHandler().addKeyBinding( "F3", findAndReplaceAction );
    getInputHandler().addKeyBinding( "A+RIGHT", new NextElementValueAction() );
    getInputHandler().addKeyBinding( "A+LEFT", new PreviousElementValueAction() );
    getInputHandler().addKeyBinding( "C+D", new DeleteLineAction() );
    getInputHandler().addKeyBinding( "S+INSERT", createPasteAction() );
    getInputHandler().addKeyBinding( "S+DELETE", createCutAction() );

    goToLineAction = new GoToLineAction();
    getInputHandler().addKeyBinding( "CA+L", goToLineAction );

    setMinimumSize( new Dimension( 50, 50 ) );
    new InternalSettingsListener( this );
  }

  @Override
  public void addNotify()
  {
    super.addNotify();
    getDocument().addUndoableEditListener( this );
  }

  @Override
  public void removeNotify()
  {
    super.removeNotify();
    getDocument().removeUndoableEditListener( this );
  }

  public Action getFindAndReplaceAction()
  {
    return findAndReplaceAction;
  }

  public Action getGoToLineAction()
  {
    return goToLineAction;
  }

  public Action getRedoAction()
  {
    return redoAction;
  }

  public Action getUndoAction()
  {
    return undoAction;
  }

  public void setText( String text )
  {
    if( text != null && text.equals( getText() ) )
      return;

    super.setText( text == null ? "" : text );

    if( discardEditsOnSet && undoManager != null )
      undoManager.discardAllEdits();
  }

  public boolean isDiscardEditsOnSet()
  {
    return discardEditsOnSet;
  }

  public void setDiscardEditsOnSet( boolean discardEditsOnSet )
  {
    this.discardEditsOnSet = discardEditsOnSet;
  }

  public UndoManager getUndoManager()
  {
    return undoManager;
  }

  public SyntaxStyle[] createXmlStyles()
  {
    SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];

    styles[Token.COMMENT1] = new SyntaxStyle( Color.black, true, false );
    styles[Token.COMMENT2] = new SyntaxStyle( new Color( 0x990033 ), true, false );
    styles[Token.KEYWORD1] = new SyntaxStyle( Color.blue, false, false );
    styles[Token.KEYWORD2] = new SyntaxStyle( Color.magenta, false, false );
    styles[Token.KEYWORD3] = new SyntaxStyle( new Color( 0x009600 ), false, false );
    styles[Token.LITERAL1] = new SyntaxStyle( new Color( 0x650099 ), false, false );
    styles[Token.LITERAL2] = new SyntaxStyle( new Color( 0x650099 ), false, true );
    styles[Token.LABEL] = new SyntaxStyle( new Color( 0x990033 ), false, true );
    styles[Token.OPERATOR] = new SyntaxStyle( Color.black, false, true );
    styles[Token.INVALID] = new SyntaxStyle( Color.red, false, true );

    return styles;
  }

  private void createUndoMananger()
  {
    undoManager = new UndoManager();
    undoManager.setLimit( UNDO_LIMIT );
  }

  /*
   *
   * private void removeUndoMananger() { if (undoManager == null) return;
   * undoManager.end(); undoManager = null; }
   */

  public void focusGained( FocusEvent fe )
  {
    if( isEditable() && undoManager == null )
      createUndoMananger();
  }

  public void setEnabledAndEditable( boolean flag )
  {
    super.setEnabled( flag );
    setEditable( flag );
  }

  public void setEditable( boolean enabled )
  {
    super.setEditable( enabled );
    setCaretVisible( enabled );
    getPainter().setLineHighlightEnabled( enabled );

    // getPainter().setBackground( enabled ? Color.WHITE : new Color(238, 238,
    // 238) );
    repaint();
  }

  public void focusLost( FocusEvent fe )
  {
    // removeUndoMananger();
  }

  public void undoableEditHappened( UndoableEditEvent e )
  {
    if( undoManager != null )
      undoManager.addEdit( e.getEdit() );
  }

  private static ReferenceQueue<JXEditTextArea> testQueue = new ReferenceQueue<JXEditTextArea>();
  private static Map<WeakReference<JXEditTextArea>, InternalSettingsListener> testMap = new HashMap<WeakReference<JXEditTextArea>, InternalSettingsListener>();

  static
  {
    new Thread( new Runnable()
    {
      public void run()
      {
        while( true )
        {
          // System.out.println(
          // "Waiting for weak references to be released.." );

          try
          {
            if( testQueue != null )
            {
              Reference<? extends JXEditTextArea> ref = testQueue.remove();
              // System.out.println( "Got ref to clear" );
              InternalSettingsListener listener = testMap.remove( ref );
              if( listener != null )
              {
                // System.out.println( "Releasing listener" );
                listener.release();
              }
              else
              {
                // System.out.println( "Listener not found" );
              }
            }
          }
          catch( InterruptedException e )
          {
            SoapUI.logError( e );
          }
        }

      }
    }, "ReferenceQueueMonitor" ).start();
  }

  private static final class InternalSettingsListener implements SettingsListener
  {
    private WeakReference<JXEditTextArea> textArea;

    public InternalSettingsListener( JXEditTextArea area )
    {
      // System.out.println( "Creating weakreference for textarea" );
      textArea = new WeakReference<JXEditTextArea>( area, testQueue );
      testMap.put( textArea, this );
      SoapUI.getSettings().addSettingsListener( this );
    }

    public void release()
    {
      if( textArea.get() == null )
      {
        SoapUI.getSettings().removeSettingsListener( this );
      }
      else
      {
        System.err.println( "Error, cannot release listener" );
      }
    }

    public void settingChanged( String name, String newValue, String oldValue )
    {
      if( name.equals( UISettings.EDITOR_FONT ) && textArea.get() != null )
      {
        textArea.get().getPainter().setFont( Font.decode( newValue ) );
        textArea.get().invalidate();
      }
    }

    @Override
    public void settingsReloaded()
    {
      // TODO Auto-generated method stub

    }

  }

  private class UndoAction extends AbstractAction
  {
    public UndoAction()
    {
      super( "Undo" );
      putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu Z" ) );
    }

    public void actionPerformed( ActionEvent e )
    {
      undo();
    }
  }

  private class RedoAction extends AbstractAction
  {
    public RedoAction()
    {
      super( "Redo" );
      putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu Y" ) );
    }

    public void actionPerformed( ActionEvent e )
    {
      redo();
    }
  }

  private final class GoToLineAction extends AbstractAction
  {
    public GoToLineAction()
    {
      super( "Go To Line" );
      putValue( Action.SHORT_DESCRIPTION, "Moves the caret to the specified line" );
      putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu alt L" ) );
    }

    public void actionPerformed( ActionEvent e )
    {
      String line = UISupport.prompt( "Enter line-number to (1.." + ( getLineCount() ) + ")", "Go To Line",
          String.valueOf( getCaretLine() + 1 ) );

      if( line != null )
      {
        try
        {
          int ln = Integer.parseInt( line ) - 1;
          if( ln >= 0 && ln < getLineCount() )
          {
            scrollTo( ln, 0 );
            setCaretPosition( getLineStartOffset( ln ) );
          }
        }
        catch( NumberFormatException e1 )
        {
        }
      }
    }
  }

  public class NextElementValueAction implements ActionListener
  {
    public void actionPerformed( ActionEvent e )
    {
      toNextElement();
    }
  }

  public class PreviousElementValueAction implements ActionListener
  {
    public void actionPerformed( ActionEvent e )
    {
      toPreviousElement();
    }
  }

  public class DeleteLineAction implements ActionListener
  {
    public void actionPerformed( ActionEvent e )
    {
      if( !isEditable() )
      {
        getToolkit().beep();
        return;
      }

      int caretLine = getCaretLine();
      if( caretLine == -1 )
        return;
      int lineStartOffset = getLineStartOffset( caretLine );
      int lineEndOffset = getLineEndOffset( caretLine );

      try
      {
        int len = lineEndOffset - lineStartOffset;
        if( lineStartOffset + len >= getDocumentLength() )
          len = getDocumentLength() - lineStartOffset;

        getDocument().remove( lineStartOffset, len );
      }
      catch( BadLocationException e1 )
      {
        SoapUI.logError( e1 );
      }
    }
  }

  public Action createCopyAction()
  {
    return new InputHandler.clip_copy();
  }

  public void undo()
  {
    if( !isEditable() )
    {
      getToolkit().beep();
      return;
    }

    try
    {
      if( undoManager != null )
        undoManager.undo();
    }
    catch( CannotUndoException cue )
    {
      Toolkit.getDefaultToolkit().beep();
    }
  }

  public Action createCutAction()
  {
    return new InputHandler.clip_cut();
  }

  public Action createPasteAction()
  {
    return new InputHandler.clip_paste();
  }

  public int getCaretColumn()
  {
    int pos = getCaretPosition();
    int line = getLineOfOffset( pos );

    return pos - getLineStartOffset( line );
  }

  public void toNextElement()
  {
    int pos = getCaretPosition();
    String text = getText();

    while( pos < text.length() )
    {
      // find ending >
      if( text.charAt( pos ) == '>' && pos < text.length() - 1
          && ( pos > 2 && !text.substring( pos - 2, pos ).equals( "--" ) )
          && ( pos > 1 && text.charAt( pos - 1 ) != '/' )
          && text.indexOf( '/', pos ) == text.indexOf( '<', pos ) + 1
          && text.lastIndexOf( '/', pos ) != text.lastIndexOf( '<', pos ) + 1 )
      {
        setCaretPosition( pos + 1 );
        return;
      }

      pos++ ;
    }

    getToolkit().beep();
  }

  public void toPreviousElement()
  {
    int pos = getCaretPosition() - 2;
    String text = getText();

    while( pos > 0 )
    {
      // find ending >
      if( text.charAt( pos ) == '>' && pos < text.length() - 1
          && ( pos > 2 && !text.substring( pos - 2, pos ).equals( "--" ) )
          && ( pos > 1 && text.charAt( pos - 1 ) != '/' )
          && text.indexOf( '/', pos ) == text.indexOf( '<', pos ) + 1
          && text.lastIndexOf( '/', pos ) != text.lastIndexOf( '<', pos ) + 1 )
      {
        setCaretPosition( pos + 1 );
        return;
      }

      pos-- ;
    }

    getToolkit().beep();
  }

  public boolean canUndo()
  {
    return undoManager != null && undoManager.canUndo();
  }

  public boolean canRedo()
  {
    return undoManager != null && undoManager.canRedo();
  }

  public void redo()
  {
    if( !isEditable() )
    {
      getToolkit().beep();
      return;
    }

    try
    {
      if( canRedo() )
        undoManager.redo();
    }
    catch( CannotRedoException cue )
    {
      Toolkit.getDefaultToolkit().beep();
    }
  }
}
TOP

Related Classes of com.eviware.soapui.support.xml.JXEditTextArea$UndoAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.