All Downloads are FREE. Search and download functionalities are using the official Maven repository.

editor.search.BaseLocalSearchDialog Maven / Gradle / Ivy

package editor.search;

import editor.undo.AtomicUndoManager;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataListener;
import javax.swing.undo.CompoundEdit;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Collections;
import java.util.regex.PatternSyntaxException;

/**
 */
public abstract class BaseLocalSearchDialog extends JDialog
{
  public static boolean g_bReplaceMode = false;
  private static final DefaultComboBoxModel g_historySearch = new DefaultComboBoxModel();
  private static final DefaultComboBoxModel g_historyReplace = new DefaultComboBoxModel();
  private static boolean g_bCaseSensitive;
  private static boolean g_bRegex;
  private JComboBox _comboSearch;
  private JComboBox _comboReplace;
  private JCheckBox _cbCaseSensitive;
  private JCheckBox _cbRegex;
  private boolean _bReplaceMode;
  private boolean _bAllMode;
  private boolean _bAllModeFromTop;
  private boolean _bStartedReplacing;
  private boolean _bDisplayNotFound;
  private String _selectedText;
  private AtomicUndoManager _undoManager;
  private CompoundEdit _undoAtom;

  public BaseLocalSearchDialog( boolean modal, boolean bReplace, String selectedText, AtomicUndoManager undoManager )
  {
    super( (JFrame)KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(), bReplace ? "Replace" : "Find", modal );
    _selectedText = selectedText;
    _bDisplayNotFound = true;
    _bReplaceMode = g_bReplaceMode = bReplace;
    _undoManager = undoManager;
    setDefaultCloseOperation( JDialog.DO_NOTHING_ON_CLOSE );
    configUI();
    addWindowListener( new WindowAdapter()
    {
      public void windowClosing( WindowEvent e )
      {
        dispose();
      }
    } );
  }

  public static boolean canRepeatFind()
  {
    return g_historySearch.getSize() > 0;
  }

  public boolean isReplaceMode()
  {
    return _bReplaceMode;
  }

  public void setReplaceMode( boolean bReplaceMode )
  {
    _bReplaceMode = bReplaceMode;
  }

  public boolean isStartedReplacing()
  {
    return _bStartedReplacing;
  }

  public void setStartedReplacing( boolean bStartedReplacing )
  {
    _bStartedReplacing = bStartedReplacing;
  }

  public void repeatFind()
  {
    _comboSearch.getEditor().setItem( g_historySearch.getElementAt( g_historySearch.getSize() - 1 ) );
    performFind( false );
  }

  public void repeatFindBackwards()
  {
    _comboSearch.getEditor().setItem( g_historySearch.getElementAt( g_historySearch.getSize() - 1 ) );
    performFind( true );
  }

  private void find( final String strText, final boolean backwards )
  {
    addTextHistory( strText, g_historySearch );
    if( isReplaceMode() )
    {
      String replaceTxt = (String)_comboReplace.getEditor().getItem();
      addTextHistory( replaceTxt, g_historyReplace );
      _comboReplace.getEditor().setItem( replaceTxt );
    }
    // Invoke later so dialog closes immediately.
    // Necessary for Replace to work write, otherwise dialog gets
    // in the way while prompting for replace.
    EventQueue.invokeLater(
      new Runnable()
      {
        public void run()
        {
          findNow( strText, backwards );
        }
      } );
  }

  /**
   * Provides a generic find method that toggles on the mode of the search dialog
   */
  protected java.util.List findInSource( String strSource, String strPattern, int iOffset, boolean backwards )
  {
    if( isRegEx() )
    {
      try
      {
        return RegExStringUtil.search( strSource, strPattern, !isCaseSensitive(), iOffset, backwards );
      }
      catch( PatternSyntaxException e )
      {
        MessageDisplay.displayError( "Invalid regular expression: " + e.getMessage() );
        return Collections.emptyList();
      }
    }
    else
    {
      return StringUtil.search( strSource, strPattern, !isCaseSensitive(), iOffset, backwards );
    }
  }

  protected void findNow( String strText, boolean backwards )
  {
    if( isReplaceMode() )
    {
      _undoAtom = null;
    }
    try
    {
      SearchLocation location = performFind( strText, backwards );
      if( location == null )
      {
        if( isDisplayNotFound() )
        {
          if( isStartedReplacing() )
          {
            MessageDisplay.displayInformation( "Finished replacing: " + strText );
          }
          else
          {
            MessageDisplay.displayInformation( "Text: " + strText );
          }
        }
      }
    }
    finally
    {
      if( isReplaceMode() && _undoAtom != null )
      {
        CompoundEdit endedAtom = null;
        while( endedAtom != _undoAtom )
        {
          endedAtom = getUndoManager().getUndoAtom();
          getUndoManager().endUndoAtom();
        }
      }
    }
  }

  protected void startUndoIfNecessary()
  {
    if( _undoAtom == null )
    {
      _undoAtom = getUndoManager().beginUndoAtom( "Replace All" );
    }
  }

  private AtomicUndoManager getUndoManager()
  {
    return _undoManager;
  }

  protected abstract SearchLocation performFind( String strText, boolean backwards );

  public boolean isDisplayNotFound()
  {
    return _bDisplayNotFound;
  }

  public void setDisplayNotFound( boolean bDisplayNotFound )
  {
    _bDisplayNotFound = bDisplayNotFound;
  }

  private void saveSettings()
  {
    g_bCaseSensitive = _cbCaseSensitive.isSelected();
    g_bRegex = _cbRegex.isSelected();
  }

  private void addTextHistory( String strText, DefaultComboBoxModel model )
  {
    if( strText == null || strText.length() == 0 )
    {
      return;
    }

    for( int i = 0; i < model.getSize(); i++ )
    {
      if( model.getElementAt( i ).equals( strText ) )
      {
        model.removeElementAt( i );
      }
    }

    model.addElement( strText );
  }

  private void initTextSettings()
  {
    _cbCaseSensitive.setSelected( g_bCaseSensitive );
    _cbRegex.setSelected( g_bRegex );
  }

  protected void configUI()
  {
    JComponent contentPane = (JComponent)getContentPane();
    contentPane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );
    contentPane.setLayout( new BorderLayout() );

    JPanel mainPanel = new JPanel( new BorderLayout() );
    mainPanel.setBorder( BorderFactory.createCompoundBorder( UIManager.getBorder( "TextField.border" ),
                                                             BorderFactory.createEmptyBorder( 5, 5, 5, 5 ) ) );
    configTextSearchUI( mainPanel );

    contentPane.add( mainPanel, BorderLayout.CENTER );

    JPanel south = new JPanel( new BorderLayout() );
    south.setBorder( BorderFactory.createEmptyBorder( 4, 0, 0, 0 ) );
    JPanel filler = new JPanel();
    south.add( filler, BorderLayout.CENTER );

    JPanel buttonPanel = new JPanel();
    buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.X_AXIS ) );

    JButton btnFind = new JButton( "Find" );
    btnFind.setMnemonic( 'F' );
    btnFind.addActionListener(
      new ActionListener()
      {
        public void actionPerformed( ActionEvent e )
        {
          performFind( false );
        }
      } );
    addFindEnabler( btnFind );
    buttonPanel.add( btnFind );
    getRootPane().setDefaultButton( btnFind );

    JButton btnCancel = new JButton( "Cancel" );
    btnCancel.addActionListener( new ActionListener()
    {
      public void actionPerformed( ActionEvent e )
      {
        close();
      }
    } );
    buttonPanel.add( btnCancel );

    south.add( buttonPanel, BorderLayout.EAST );
    contentPane.add( south, BorderLayout.SOUTH );

    mapCancelKeystroke();

    setSize( 400, 300 );
    setResizable( false );

    StudioUtilities.centerWindowInFrame( this, getOwner() );

    EventQueue.invokeLater(
      new Runnable()
      {
        public void run()
        {
          if( _comboSearch.isShowing() )
          {
            _comboSearch.requestFocus();
          }
        }
      } );
  }

  private void addFindEnabler( final JButton btnFind )
  {
    enableFindButton( btnFind );

    _comboSearch.getEditor().addActionListener(
      new ActionListener()
      {
        public void actionPerformed( ActionEvent e )
        {
          enableFindButton( btnFind );
          if( btnFind.isEnabled() && !_comboSearch.isPopupVisible() )
          {
            btnFind.doClick();
          }
        }
      } );
    _comboSearch.addActionListener( new ActionListener()
    {
      public void actionPerformed( ActionEvent e )
      {
        enableFindButton( btnFind );
      }
    } );

    if( _comboReplace != null )
    {
      _comboReplace.getEditor().addActionListener(
        new ActionListener()
        {
          public void actionPerformed( ActionEvent e )
          {
            enableFindButton( btnFind );
            if( btnFind.isEnabled() && !_comboReplace.isPopupVisible() )
            {
              btnFind.doClick();
            }
          }
        } );
      _comboReplace.addActionListener( new ActionListener()
      {
        public void actionPerformed( ActionEvent e )
        {
          enableFindButton( btnFind );
        }
      } );
    }

    ((JTextField)_comboSearch.getEditor().getEditorComponent()).getDocument().addDocumentListener(
      new DocumentListener()
      {
        public void changedUpdate( DocumentEvent e )
        {
        }

        public void insertUpdate( DocumentEvent e )
        {
          enableFindButton( btnFind );
        }

        public void removeUpdate( DocumentEvent e )
        {
          enableFindButton( btnFind );
        }
      } );
  }

  private void enableFindButton( final JButton btnFind )
  {
    String strText = (String)_comboSearch.getEditor().getItem();
    btnFind.setEnabled( strText != null && strText.length() > 0 );
  }

  private void performFind( boolean backwards )
  {
    findText( backwards );
    saveSettings();
    close();
  }

  /**
   * @param contentPane
   */
  private void configTextSearchUI( JComponent contentPane )
  {
    JPanel north = new JPanel( new BorderLayout() );

    JPanel textSearchPanel = new JPanel();
    textSearchPanel.setLayout( new BoxLayout( textSearchPanel, BoxLayout.Y_AXIS ) );
    JPanel nameValue = new JPanel( new BorderLayout() );
    JLabel label = new JLabel( "Text to find" );
    nameValue.add( label, BorderLayout.NORTH );
    for( ListDataListener listener : g_historySearch.getListDataListeners() )
    {
      g_historySearch.removeListDataListener( listener );
    }
    _comboSearch = new JComboBox( g_historySearch );
    _comboSearch.setEditable( true );
    JTextField textField = (JTextField)_comboSearch.getEditor().getEditorComponent();

    if( _selectedText != null && !_selectedText.isEmpty() )
    {
      textField.setText( _selectedText );
    }
    else if( g_historySearch.getSize() > 0 )
    {
      _comboSearch.getEditor().setItem( g_historySearch.getElementAt( g_historySearch.getSize() - 1 ) );
    }
    textField.setSelectionStart( 0 );
    textField.setSelectionEnd( textField.getText().length() );

    nameValue.add( _comboSearch, BorderLayout.SOUTH );
    textSearchPanel.add( nameValue );

    if( isReplaceMode() )
    {
      nameValue = new JPanel( new BorderLayout() );
      label = new JLabel( "Replace with" );
      nameValue.add( label, BorderLayout.NORTH );
      _comboReplace = new JComboBox( g_historyReplace );
      _comboReplace.setEditable( true );
      if( g_historyReplace.getSelectedItem() != null )
      {
        ((JTextField)_comboReplace.getEditor().getEditorComponent()).setText( g_historyReplace.getSelectedItem().toString() );
      }
      nameValue.add( _comboReplace, BorderLayout.SOUTH );
      textSearchPanel.add( nameValue );
    }

    north.add( textSearchPanel, BorderLayout.SOUTH );

    contentPane.add( north, BorderLayout.NORTH );

    JPanel center = new JPanel();
    center.setBorder( BorderFactory.createEmptyBorder( 10, 0, 0, 0 ) );
    center.setLayout( new BoxLayout( center, BoxLayout.Y_AXIS ) );

    center.add( new JSeparator() );

    _cbCaseSensitive = new JCheckBox( "Case sensitive" );
    _cbCaseSensitive.setMnemonic( 'C' );
    center.add( _cbCaseSensitive );

    _cbRegex = new JCheckBox( "Regular expression" );
    _cbRegex.setMnemonic( 'R' );
    center.add( _cbRegex );

    contentPane.add( center, BorderLayout.CENTER );

    initTextSettings();
  }

  private final void close()
  {
    dispose();
  }

  private void findText( boolean backwards )
  {
    String strText = (String)_comboSearch.getEditor().getItem();
    if( (strText == null || strText.length() == 0) )
    {
      return;
    }
    find( strText, backwards );
  }

  private void mapCancelKeystroke()
  {
    Object key = getRootPane().getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).get( KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ) );
    if( key == null )
    {
      key = "Cancel";
      getRootPane().getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), key );
    }
    getRootPane().getActionMap().put( key,
                                      new AbstractAction()
                                      {
                                        public void actionPerformed( ActionEvent e )
                                        {
                                          close();
                                        }
                                      } );
  }

  public boolean isCaseSensitive()
  {
    return _cbCaseSensitive.isSelected();
  }

  public boolean isRegEx()
  {
    return _cbRegex.isSelected();
  }

  public boolean isAllMode()
  {
    return _bAllMode;
  }

  public void setAllMode( boolean bAllMode )
  {
    _bAllMode = bAllMode;
  }

  public boolean hasAllModeRecycledFromTop()
  {
    return _bAllModeFromTop;
  }

  public void setAllModeRecyclingFromTop( boolean bAllModeFromTop )
  {
    _bAllModeFromTop = bAllModeFromTop;
  }

  public String getDialogReplaceText()
  {
    return (String)_comboReplace.getEditor().getItem();
  }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy