/**
*
*/
package org.goko.tools.editor.handlers.findreplace;
import java.util.function.Supplier;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.text.IFindReplaceTarget;
import org.eclipse.jface.util.Util;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.wb.swt.ResourceManager;
/**
* @author Psyko
* @date 30 mai 2016
*/
public class GCodeFindReplaceDialog extends Dialog {
/** The string to find */
private Text findString;
/** The replacement string*/
private Text replaceString;
/** The find replace target */
private Supplier<IFindReplaceTarget> findReplaceTargetSupplier;
private Button btnRadioForward;
private Button btnCaseSensitive;
private Button btnWholeWord;
/** Position of the last match. <code>null</code> if none found */
private Point lastFoundMatch;
private Button findButton;
private Button replaceFindButton;
private Button replaceButton;
private Button replaceAllButton;
private Label lblResult;
private Button btnWrapSearch;
private Composite composite_3;
/**
* Create the dialog.
* @param parentShell
*/
public GCodeFindReplaceDialog(Shell parentShell, Supplier<IFindReplaceTarget> findReplaceTargetSupplier) {
super(parentShell);
setBlockOnOpen(false);
setShellStyle(SWT.CLOSE);
this.findReplaceTargetSupplier = findReplaceTargetSupplier;
}
/** (inheritDoc)
* @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
*/
@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText("Find/replace");
newShell.setImage(ResourceManager.getPluginImage("org.goko.tools.editor", "resources/icons/clipboard-search-result.png"));
}
/**
* Create contents of the dialog.
* @param parent
*/
@Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
GridLayout gl_container = new GridLayout(1, false);
gl_container.marginHeight = 0;
gl_container.horizontalSpacing = 0;
container.setLayout(gl_container);
Composite composite = new Composite(container, SWT.NONE);
composite.setLayout(new GridLayout(2, false));
composite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
Label lblFind = new Label(composite, SWT.NONE);
lblFind.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
lblFind.setText("Find: ");
findString = new Text(composite, SWT.BORDER);
findString.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
if(findReplaceTargetSupplier != null && findReplaceTargetSupplier.get() != null){
findString.setText(findReplaceTargetSupplier.get().getSelectionText());
}
Label lblReplace = new Label(composite, SWT.NONE);
lblReplace.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
lblReplace.setText("Replace:");
replaceString = new Text(composite, SWT.BORDER);
replaceString.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
Composite composite_2 = new Composite(container, SWT.NONE);
GridLayout gl_composite_2 = new GridLayout(2, true);
gl_composite_2.marginWidth = 0;
gl_composite_2.marginHeight = 0;
composite_2.setLayout(gl_composite_2);
composite_2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1));
Group grpOptions = new Group(composite_2, SWT.NONE);
grpOptions.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true, 1, 1));
grpOptions.setLayout(new GridLayout(2, false));
grpOptions.setText("Options");
btnCaseSensitive = new Button(grpOptions, SWT.CHECK);
btnCaseSensitive.setText("Case sensitive");
btnWrapSearch = new Button(grpOptions, SWT.CHECK);
btnWrapSearch.setText("Wrap search");
btnWholeWord = new Button(grpOptions, SWT.CHECK);
btnWholeWord.setText("Whole word");
new Label(grpOptions, SWT.NONE);
Group grpDirection = new Group(composite_2, SWT.NONE);
grpDirection.setLayout(new GridLayout(1, false));
grpDirection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
grpDirection.setText("Direction");
btnRadioForward = new Button(grpDirection, SWT.RADIO);
btnRadioForward.setSelection(true);
btnRadioForward.setText("Forward");
Button btnRadioBackward = new Button(grpDirection, SWT.RADIO);
btnRadioBackward.setText("Backward");
composite_3 = new Composite(container, SWT.NONE);
composite_3.setLayout(new GridLayout(2, false));
composite_3.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
lblResult = new Label(composite_3, SWT.NONE);
lblResult.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
lblResult.setText(StringUtils.EMPTY);
Composite composite_1 = new Composite(composite_3, SWT.NONE);
composite_1.setLayoutData(new GridData(SWT.RIGHT, SWT.BOTTOM, false, true, 1, 1));
GridLayout gl_composite_1 = new GridLayout(2, false);
gl_composite_1.numColumns = -2;
gl_composite_1.marginRight = 5;
gl_composite_1.marginHeight = 0;
gl_composite_1.marginWidth = 0;
composite_1.setLayout(gl_composite_1);
findButton = createButton(composite_1, 600, "Find", true);
replaceFindButton = createButton(composite_1, 601, "Replace/Find", false);
replaceButton = createButton(composite_1, 602, "Replace", false);
replaceAllButton = createButton(composite_1, 603, "Replace all", false);
replaceButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
performReplace();
}
});
replaceAllButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
performReplaceAll();
}
});
findButton.addSelectionListener(new SelectionAdapter() {
/** (inheritDoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
performFind();
}
});
container.addTraverseListener(new TraverseListener() {
@Override
public void keyTraversed(TraverseEvent e) {
if (e.detail == SWT.TRAVERSE_RETURN) {
if (!Util.isMac()) {
Control controlWithFocus= getShell().getDisplay().getFocusControl();
if (controlWithFocus != null && (controlWithFocus.getStyle() & SWT.PUSH) == SWT.PUSH)
return;
}
Event event= new Event();
event.type= SWT.Selection;
event.stateMask = e.stateMask;
findButton.notifyListeners(SWT.Selection, event);
e.doit= false;
}
}
});
replaceFindButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
performReplaceFind();
}
});
findString.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
setLastFoundMatch(null);
updateButtonState();
}
});
updateButtonState();
return container;
}
/**
* Create contents of the button bar.
* @param parent
*/
@Override
protected void createButtonsForButtonBar(Composite parent) {
Button closeButton = createButton(parent, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL, false);
closeButton.addSelectionListener(new SelectionAdapter() {
/** (inheritDoc)
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
close();
}
});
}
protected void updateButtonState(){
findButton.setEnabled(!StringUtils.isEmpty(getSearchString()));
replaceAllButton.setEnabled(!StringUtils.isEmpty(getSearchString()));
// Manage button state
replaceButton.setEnabled(isReplacePossible());
replaceFindButton.setEnabled(isReplacePossible());
}
/**
* Return the initial size of the dialog.
*/
@Override
protected Point getInitialSize() {
return new Point(450, 300);
}
private void findIndex(int startIndex, boolean wrapped){
int foundPosition = getFindRplaceTarget().findAndSelect(startIndex, getSearchString(), isForwardSearch(), isCaseSensitiveSearch(), isWholeWordSearch());
// Memorize the found match
if(foundPosition != -1){
setLastFoundMatch(new Point(foundPosition, StringUtils.length(getSearchString())));
lblResult.setText(StringUtils.EMPTY);
}else{
if(getLastFoundMatch() == null){ // It means the string was not found so far
lblResult.setText("String not found");
}else{
lblResult.setText("End of document reached");
}
setLastFoundMatch(null);
getShell().getDisplay().beep();
if(isWrapSearch() && !wrapped){
findIndex(-1, true);
}
}
}
/**
* Perform the actual search for the given search string
*/
private void performFind(){
int position = getFindRplaceTarget().getSelection().x;
if(isForwardSearch()){
position += getFindRplaceTarget().getSelection().y;
}
findIndex(position, false);
updateButtonState();
}
/**
* Perform the actual replace of the found String
*/
private void performReplace(){
if(isReplacePossible()){
getFindRplaceTarget().replaceSelection(getReplaceString());
setLastFoundMatch(null);
}
updateButtonState();
}
/**
* Perform the actual replace and find
*/
private void performReplaceFind(){
if(isReplacePossible()){
getFindRplaceTarget().replaceSelection(getReplaceString());
setLastFoundMatch(null);
performFind();
}
updateButtonState();
}
/**
* Perform the actual replace all
*/
private void performReplaceAll(){
// Initiate first find
if(lastFoundMatch == null){
performFind();
}
while (isReplacePossible()) {
performReplaceFind();
}
}
private IFindReplaceTarget getFindRplaceTarget(){
return findReplaceTargetSupplier.get();
}
private boolean isForwardSearch(){
return btnRadioForward.getSelection();
}
private boolean isWholeWordSearch(){
return btnWholeWord.getSelection();
}
private boolean isCaseSensitiveSearch(){
return btnCaseSensitive.getSelection();
}
private boolean isWrapSearch(){
return btnWrapSearch.getSelection();
}
private String getSearchString(){
return findString.getText();
}
private String getReplaceString(){
return replaceString.getText();
}
/**
* @return the replacePossible
*/
public boolean isReplacePossible() {
return lastFoundMatch != null;
}
/**
* @return the lastFoundMatch
*/
public Point getLastFoundMatch() {
return lastFoundMatch;
}
/**
* @param lastFoundMatch the lastFoundMatch to set
*/
public void setLastFoundMatch(Point lastFoundMatch) {
this.lastFoundMatch = lastFoundMatch;
}
}