blob: fd95f5a50c89072565f4f2f675accd5c8f4678bd [file] [log] [blame]
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
package org.eclipse.ui.texteditor;
import java.text.MessageFormat;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.text.IFindReplaceTarget;
import org.eclipse.jface.text.IFindReplaceTargetExtension;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextListener;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITextViewerExtension;
import org.eclipse.jface.text.TextEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
/**
* An incremental find target. Replace is always disabled.
*/
class IncrementalFindTarget implements IFindReplaceTarget, IFindReplaceTargetExtension, VerifyKeyListener, MouseListener, FocusListener, ITextListener {
/** The string representing rendered tab */
private final static String TAB= EditorMessages.getString("Editor.FindIncremental.render.tab"); //$NON-NLS-1$
/** The text viewer to operate on */
private final ITextViewer fTextViewer;
/** The status line manager for output */
private final IStatusLineManager fStatusLine;
/** The find replace target to delegate find requests */
private final IFindReplaceTarget fTarget;
/** The current find string */
private StringBuffer fFindString= new StringBuffer();
/** The position to start the find from */
private int fBasePosition;
/** The position of the first upper case character, -1 if none */
private int fCasePosition;
/** The position of the last successful find */
private int fCurrentIndex;
/** A flag indicating if last find was successful */
private boolean fFound;
/** A flag indicating listeners are installed. */
private boolean fInstalled;
/**
* Creates an instance of an incremental find target.
*
* @param viewer the text viewer to operate on
* @param manager the status line manager for output
*/
public IncrementalFindTarget(ITextViewer viewer, IStatusLineManager manager) {
fTextViewer= viewer;
fStatusLine= manager;
fTarget= viewer.getFindReplaceTarget();
}
/*
* @see IFindReplaceTarget#canPerformFind()
*/
public boolean canPerformFind() {
return fTarget.canPerformFind();
}
/*
* @see IFindReplaceTarget#findAndSelect(int, String, boolean, boolean, boolean)
*/
public int findAndSelect(int offset, String findString, boolean searchForward, boolean caseSensitive, boolean wholeWord) {
return fTarget.findAndSelect(offset, findString, searchForward, caseSensitive, wholeWord);
}
/*
* @see IFindReplaceTarget#getSelection()
*/
public Point getSelection() {
return fTarget.getSelection();
}
/*
* @see IFindReplaceTarget#getSelectionText()
*/
public String getSelectionText() {
return fTarget.getSelectionText();
}
/*
* @see IFindReplaceTarget#isEditable()
*/
public boolean isEditable() {
return false;
}
/*
* @see IFindReplaceTarget#replaceSelection(String)
*/
public void replaceSelection(String text) {
}
/*
* @see IFindReplaceTargetExtension#beginSession()
*/
public void beginSession() {
fFindString.setLength(0);
fCasePosition= -1;
fBasePosition= fTarget.getSelection().x;
fCurrentIndex= fBasePosition;
fFound= true;
install();
performFindNext(true, fBasePosition);
if (fTarget instanceof IFindReplaceTargetExtension)
((IFindReplaceTargetExtension) fTarget).beginSession();
}
/*
* @see IFindReplaceTargetExtension#endSession()
*/
public void endSession() {
if (fTarget instanceof IFindReplaceTargetExtension)
((IFindReplaceTargetExtension) fTarget).endSession();
// will uninstall itself
}
/*
* @see IFindReplaceTargetExtension#getScope()
*/
public IRegion getScope() {
return null;
}
/*
* @see IFindReplaceTargetExtension#setGlobal(boolean)
*/
public void setGlobal(boolean global) {
}
/*
* @see IFindReplaceTargetExtension#setScope(IRegion)
*/
public void setScope(IRegion scope) {
}
private void install() {
if (fInstalled)
return;
StyledText text= fTextViewer.getTextWidget();
if (text == null)
return;
text.addMouseListener(this);
fTextViewer.addTextListener(this);
if (fTextViewer instanceof ITextViewerExtension) {
ITextViewerExtension e= (ITextViewerExtension) fTextViewer;
e.prependVerifyKeyListener(this);
} else {
text.addVerifyKeyListener(this);
}
fInstalled= true;
}
private void uninstall() {
fTextViewer.removeTextListener(this);
StyledText text= fTextViewer.getTextWidget();
text.removeMouseListener(this);
if (fTextViewer instanceof ITextViewerExtension) {
ITextViewerExtension e= (ITextViewerExtension) fTextViewer;
e.removeVerifyKeyListener(this);
} else {
text.removeVerifyKeyListener(this);
}
fInstalled= false;
}
private void performFindNext(boolean forward, int position) {
String string= fFindString.toString();
int index;
if (string.length() == 0) {
// workaround for empty selection in target
fTextViewer.setSelectedRange(fBasePosition + fTextViewer.getVisibleRegion().getOffset(), 0);
index= fBasePosition;
} else {
if (!forward)
position--;
index= findIndex(string, position, forward, fCasePosition != -1, true);
}
if (index == -1) {
if (fFound) {
// beep once
fFound= false;
fTextViewer.getTextWidget().getDisplay().beep();
}
String pattern= EditorMessages.getString("Editor.FindIncremental.not_found.pattern"); //$NON-NLS-1$
statusError(MessageFormat.format(pattern, new Object[] { string }));
} else {
fFound= true;
fCurrentIndex= index;
String pattern= EditorMessages.getString("Editor.FindIncremental.found.pattern"); //$NON-NLS-1$
statusMessage(MessageFormat.format(pattern, new Object[] { string }));
}
}
private int findIndex(String findString, int startPosition, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch) {
if (forwardSearch) {
if (wrapSearch) {
int index= fTarget.findAndSelect(startPosition, findString, true, caseSensitive, false);
if (index == -1)
index= fTarget.findAndSelect(-1, findString, true, caseSensitive, false);
return index;
}
return fTarget.findAndSelect(startPosition, findString, true, caseSensitive, false);
}
// backward
if (wrapSearch) {
int index= fTarget.findAndSelect(startPosition - 1, findString, false, caseSensitive, false);
if (index == -1) {
index= fTarget.findAndSelect(-1, findString, false, caseSensitive, false);
}
return index;
}
return fTarget.findAndSelect(startPosition - 1, findString, false, caseSensitive, false);
}
/*
* @see VerifyKeyListener#verifyKey(VerifyEvent)
*/
public void verifyKey(VerifyEvent event) {
if (!event.doit)
return;
if (event.character == 0) {
switch (event.keyCode) {
// ALT, CTRL, ARROW_LEFT, ARROW_RIGHT == leave
case SWT.ALT:
case SWT.CTRL:
case SWT.ARROW_LEFT:
case SWT.ARROW_RIGHT:
leave();
break;
// find next
case SWT.ARROW_DOWN:
performFindNext(true, fTarget.getSelection().x + fTarget.getSelection().y);
event.doit= false;
break;
// find previous
case SWT.ARROW_UP:
performFindNext(false, fTarget.getSelection().x);
if (fCurrentIndex != -1 && fCurrentIndex < fBasePosition)
fBasePosition= fCurrentIndex;
event.doit= false;
break;
}
// event.character != 0
} else {
switch (event.character) {
// ESC, CR = quit
case 0x1B:
case 0x0D:
leave();
event.doit= false;
break;
// backspace and delete
case 0x08:
case 0x7F:
{
int length= fFindString.length();
if (length == 0) {
fTextViewer.getTextWidget().getDisplay().beep();
event.doit= false;
break;
} else {
fFindString.replace(length - 1, length, ""); //$NON-NLS-1$
}
if (fCasePosition == fFindString.length())
fCasePosition= -1;
performFindNext(true, fBasePosition);
event.doit= false;
}
break;
default:
if (event.stateMask == 0 || event.stateMask == SWT.SHIFT) {
char character= event.character;
if (fCasePosition == -1 && Character.isUpperCase(character) && Character.toLowerCase(character) != character)
fCasePosition= fFindString.length();
fFindString.append(character);
performFindNext(true, fBasePosition);
event.doit= false;
}
break;
}
}
}
private void leave() {
statusClear();
uninstall();
}
/*
* @see ITextListener#textChanged(TextEvent)
*/
public void textChanged(TextEvent event) {
leave();
}
/*
* @see MouseListener#mouseDoubleClick(MouseEvent)
*/
public void mouseDoubleClick(MouseEvent e) {
leave();
}
/*
* @see MouseListener#mouseDown(MouseEvent)
*/
public void mouseDown(MouseEvent e) {
leave();
}
/*
* @see MouseListener#mouseUp(MouseEvent)
*/
public void mouseUp(MouseEvent e) {
leave();
}
/*
* @see FocusListener#focusGained(FocusEvent)
*/
public void focusGained(FocusEvent e) {
leave();
}
/*
* @see FocusListener#focusLost(FocusEvent)
*/
public void focusLost(FocusEvent e) {
leave();
}
private void statusMessage(String string) {
fStatusLine.setErrorMessage(""); //$NON-NLS-1$
fStatusLine.setMessage(escapeTabs(string));
}
private void statusError(String string) {
fStatusLine.setErrorMessage(escapeTabs(string));
fStatusLine.setMessage(""); //$NON-NLS-1$
}
private void statusClear() {
fStatusLine.setErrorMessage(""); //$NON-NLS-1$
fStatusLine.setMessage(""); //$NON-NLS-1$
}
private String escapeTabs(String string) {
StringBuffer buffer= new StringBuffer();
int begin= 0;
int end= string.indexOf('\t', begin);
while (end >= 0) {
buffer.append(string.substring(begin, end));
buffer.append(TAB);
begin= end + 1;
end= string.indexOf('\t', begin);
}
buffer.append(string.substring(begin));
return buffer.toString();
}
/*
* @see IFindReplaceTargetExtension#getLineSelection()
*/
public Point getLineSelection() {
if (fTarget instanceof IFindReplaceTargetExtension)
return ((IFindReplaceTargetExtension) fTarget).getLineSelection();
return null; // XXX should not return null
}
/*
* @see IFindReplaceTargetExtension#setSelection(int, int)
*/
public void setSelection(int offset, int length) {
if (fTarget instanceof IFindReplaceTargetExtension)
((IFindReplaceTargetExtension) fTarget).setSelection(offset, length);
}
/*
* @see IFindReplaceTargetExtension#setScopeHighlightColor(Color)
*/
public void setScopeHighlightColor(Color color) {
}
}