/*******************************************************************************
* Copyright (c) 2012, 2016 Original authors and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Original authors and others - initial API and implementation
* Dirk Fauth <dirk.fauth@googlemail.com> - Bug 453914
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.search.gui;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.regex.PatternSyntaxException;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.resource.JFaceColors;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.nebula.widgets.nattable.Messages;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.command.ILayerCommand;
import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate;
import org.eclipse.nebula.widgets.nattable.layer.CompositeLayer;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.ILayerListener;
import org.eclipse.nebula.widgets.nattable.layer.cell.CellDisplayConversionUtils;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;
import org.eclipse.nebula.widgets.nattable.search.ISearchDirection;
import org.eclipse.nebula.widgets.nattable.search.action.SearchAction;
import org.eclipse.nebula.widgets.nattable.search.command.SearchCommand;
import org.eclipse.nebula.widgets.nattable.search.event.SearchEvent;
import org.eclipse.nebula.widgets.nattable.search.strategy.GridSearchStrategy;
import org.eclipse.nebula.widgets.nattable.search.strategy.ISearchStrategy;
import org.eclipse.nebula.widgets.nattable.search.strategy.SelectionSearchStrategy;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
import org.eclipse.nebula.widgets.nattable.selection.command.ClearAllSelectionsCommand;
import org.eclipse.nebula.widgets.nattable.selection.command.SelectCellCommand;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
/**
* Find Dialog. Borrows from
* <code>org.eclipse.ui.texteditor.FindReplaceDialog</code>. Used internally by
* {@link SearchAction}.
*/
public class SearchDialog extends Dialog {
private class SelectionItem {
String text;
PositionCoordinate pos;
SelectionItem(String text, PositionCoordinate pos) {
this.text = text;
this.pos = new PositionCoordinate(pos);
}
}
private NatTable natTable;
private SelectionLayer selectionLayer;
private Comparator<?> comparator;
/**
* A stack for recording selections. In incremental mode, the stack is used
* when the search term is shortened. In non-incremental mode, the stack
* contains only the most recent selection.
*/
private Stack<SelectionItem> selections = new Stack<SelectionItem>();
// Dialog settings
private IDialogSettings originalSettings;
private IDialogSettings dialogSettings;
private IDialogSettings dialogBounds;
private Rectangle dialogPositionValue;
// Find Combo box
private Combo findCombo;
private List<String> findHistory = new ArrayList<String>(5);
// Direction radio
private Button forwardButton;
private boolean forwardValue = true;
// Scope radio
private Button allButton;
private boolean allValue = true;
private Button selectionButton;
// Options and cached values.
private Button caseSensitiveButton;
private boolean caseSensitiveValue;
private Button wrapSearchButton;
private boolean wrapSearchValue = true;
private Button wholeWordButton;
private boolean wholeWordValue;
private Button incrementalButton;
private boolean incrementalValue;
private Button columnFirstButton;
private boolean columnFirstValue;
// TODO
// private Button includeCollapsedButton;
// private boolean includeCollapsedValue = true;
private Button regexButton;
private boolean regexValue;
// Status label
private Label statusLabel;
// Find button
private Button findButton;
private ModifyListener findComboModifyListener;
public SearchDialog(Shell shell, Comparator<?> comparator, int style) {
super(shell);
this.comparator = comparator;
setShellStyle(getShellStyle() ^ style | SWT.MODELESS);
setBlockOnOpen(false);
}
public void setInput(NatTable natTable, IDialogSettings settings) {
if (natTable != null && natTable.equals(this.natTable)) {
return;
}
this.natTable = natTable;
if (natTable != null) {
ILayer result = findSelectionLayer(this.natTable.getLayer());
if (result != null && result instanceof SelectionLayer) {
this.selectionLayer = (SelectionLayer) result;
if (this.findButton != null && !this.findButton.isDisposed()) {
this.findButton.setEnabled(true);
}
}
} else {
this.selectionLayer = null;
if (this.findButton != null && !this.findButton.isDisposed()) {
this.findButton.setEnabled(false);
}
}
this.originalSettings = settings;
if (settings == null) {
this.dialogSettings = null;
this.dialogBounds = null;
} else {
this.dialogSettings = settings.getSection(getClass().getName());
if (this.dialogSettings == null) {
this.dialogSettings = settings.addNewSection(getClass().getName());
}
String boundsName = getClass().getName() + "_dialogBounds"; //$NON-NLS-1$
this.dialogBounds = settings.getSection(boundsName);
if (this.dialogBounds == null) {
this.dialogBounds = settings.addNewSection(boundsName);
}
}
readConfiguration();
}
@Override
protected boolean isResizable() {
return true;
}
/**
* @since 1.5
*/
public boolean isModal() {
return (getShellStyle() & SWT.APPLICATION_MODAL) != 0;
}
/**
* @since 1.5
*/
public NatTable getNatTable() {
return this.natTable;
}
/**
* @since 1.5
*/
public IDialogSettings getOriginalDialogSettings() {
return this.originalSettings;
}
@Override
public void create() {
super.create();
getShell().setText(Messages.getString("Search.find")); //$NON-NLS-1$
// set dialog position
if (this.dialogPositionValue != null) {
getShell().setBounds(this.dialogPositionValue);
}
this.findCombo.removeModifyListener(this.findComboModifyListener);
updateCombo(this.findCombo, this.findHistory);
this.findCombo.addModifyListener(this.findComboModifyListener);
// search SelectionLayer in layer stack
ILayer result = findSelectionLayer(this.natTable.getLayer());
if (result != null && result instanceof SelectionLayer) {
this.selectionLayer = (SelectionLayer) result;
}
// Pick the user's selection, if possible
PositionCoordinate pos = getPosition();
final String text = getTextForSelection(pos);
this.selections.push(new SelectionItem(text, pos));
this.findCombo.setText(text);
}
private ILayer findSelectionLayer(ILayer layer) {
if (layer == null || layer instanceof SelectionLayer) {
return layer;
} else if (layer instanceof CompositeLayer) {
// if the layer is a CompositeLayer, search for the SelectionLayer
// in every region as the SelectionLayer is typically placed in the
// bottom/right most region (e.g. the body in a grid, the search is
// performed backwards
CompositeLayer composite = (CompositeLayer) layer;
for (int x = composite.getLayoutXCount(); x >= 0; x--) {
for (int y = composite.getLayoutYCount(); y >= 0; y--) {
ILayer childStack = composite.getChildLayerByLayoutCoordinate(x, y);
ILayer result = findSelectionLayer(childStack);
if (result instanceof SelectionLayer) {
return result;
}
}
}
return null;
} else {
return findSelectionLayer(layer.getUnderlyingLayerByPosition(0, 0));
}
}
private String getTextForSelection(PositionCoordinate selection) {
if (this.selectionLayer == null
|| selection == null
|| selection.columnPosition == SelectionLayer.NO_SELECTION) {
return ""; //$NON-NLS-1$
}
final ILayerCell cell = this.selectionLayer.getCellByPosition(selection.columnPosition, selection.rowPosition);
if (cell == null || cell.getDataValue() == null) {
return ""; //$NON-NLS-1$
} else if (this.natTable != null) {
return CellDisplayConversionUtils.convertDataType(cell, this.natTable.getConfigRegistry());
}
return cell.getDataValue().toString();
}
@Override
public boolean close() {
storeSettings();
return super.close();
}
/**
* Stores the current state in the dialog settings.
*/
private void storeSettings() {
if (getShell() == null || getShell().isDisposed()) {
return;
}
this.dialogPositionValue = getShell().getBounds();
this.forwardValue = this.forwardButton.getSelection();
this.allValue = this.allButton.getSelection();
this.caseSensitiveValue = this.caseSensitiveButton.getSelection();
this.wrapSearchValue = this.wrapSearchButton.getSelection();
this.wholeWordValue = this.wholeWordButton.getSelection();
this.incrementalValue = this.incrementalButton.getSelection();
this.regexValue = this.regexButton.getSelection();
// TODO
// includeCollapsedValue = includeCollapsedButton.getSelection();
this.columnFirstValue = this.columnFirstButton.getSelection();
writeConfiguration();
}
@Override
protected Control createContents(final Composite parent) {
final Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
.grab(true, false).applyTo(createInputPanel(composite));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
.grab(true, false).applyTo(createOptionsPanel(composite));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
.grab(true, true).applyTo(createStatusPanel(composite));
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.BOTTOM)
.grab(true, true).applyTo(createButtonSection(composite));
return composite;
}
private Composite createStatusPanel(Composite composite) {
Composite panel = new Composite(composite, SWT.NONE);
panel.setLayout(new GridLayout(1, false));
this.statusLabel = new Label(panel, SWT.LEFT);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).applyTo(this.statusLabel);
return panel;
}
private Composite createButtonSection(Composite composite) {
Composite panel = new Composite(composite, SWT.NONE);
GridLayout layout = new GridLayout(1, false);
panel.setLayout(layout);
Label label = new Label(panel, SWT.LEFT);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).applyTo(label);
this.findButton = createButton(
panel,
IDialogConstants.CLIENT_ID,
Messages.getString("Search.findButtonLabel"), false); //$NON-NLS-1$
int buttonWidth = getButtonWidthHint(this.findButton);
GridDataFactory.swtDefaults().align(SWT.RIGHT, SWT.BOTTOM)
.grab(false, false).hint(buttonWidth, SWT.DEFAULT)
.applyTo(this.findButton);
this.findButton.setEnabled(false);
getShell().setDefaultButton(this.findButton);
this.findButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
doFind();
}
});
Button closeButton = createButton(panel, IDialogConstants.CANCEL_ID,
Messages.getString("Search.closeButtonLabel"), false); //$NON-NLS-1$
buttonWidth = getButtonWidthHint(closeButton);
GridDataFactory.swtDefaults().align(SWT.RIGHT, SWT.BOTTOM)
.grab(false, false).hint(buttonWidth, SWT.DEFAULT)
.applyTo(closeButton);
return panel;
}
public static int getButtonWidthHint(Button button) {
button.setFont(JFaceResources.getDialogFont());
PixelConverter converter = new PixelConverter(button);
int widthHint = converter.convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
return Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
}
private Composite createInputPanel(final Composite composite) {
final Composite row = new Composite(composite, SWT.NONE);
row.setLayout(new GridLayout(2, false));
final Label findLabel = new Label(row, SWT.NONE);
findLabel.setText(Messages.getString("Search.findLabel") + ":"); //$NON-NLS-1$ //$NON-NLS-2$
GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER)
.applyTo(findLabel);
this.findCombo = new Combo(row, SWT.DROP_DOWN | SWT.BORDER);
GridDataFactory.fillDefaults().grab(true, false).applyTo(this.findCombo);
this.findComboModifyListener = new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
if (SearchDialog.this.allValue && SearchDialog.this.incrementalButton.isEnabled()
&& SearchDialog.this.incrementalButton.getSelection()) {
doIncrementalFind();
}
SearchDialog.this.findButton.setEnabled(SearchDialog.this.findCombo.getText().length() > 0 && SearchDialog.this.selectionLayer != null);
}
};
this.findCombo.addModifyListener(this.findComboModifyListener);
this.findCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
if (SearchDialog.this.findButton.isEnabled()) {
doFind();
}
}
});
return row;
}
private Composite createOptionsPanel(final Composite composite) {
final Composite row = new Composite(composite, SWT.NONE);
row.setLayout(new GridLayout(2, true));
final Group directionGroup = new Group(row, SWT.SHADOW_ETCHED_IN);
GridDataFactory.fillDefaults().grab(true, true).applyTo(directionGroup);
directionGroup.setText(Messages.getString("Search.direction")); //$NON-NLS-1$
RowLayout rowLayout = new RowLayout(SWT.VERTICAL);
rowLayout.marginHeight = rowLayout.marginWidth = 3;
directionGroup.setLayout(rowLayout);
this.forwardButton = new Button(directionGroup, SWT.RADIO);
this.forwardButton.setText(Messages.getString("Search.forwardButtonLabel")); //$NON-NLS-1$
this.forwardButton.setSelection(this.forwardValue);
this.forwardButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (SearchDialog.this.incrementalButton.getSelection()) {
resetIncrementalSelections();
}
}
});
final Button backwardButton = new Button(directionGroup, SWT.RADIO);
backwardButton.setText(Messages.getString("Search.backwardButtonLabel")); //$NON-NLS-1$
backwardButton.setSelection(!this.forwardValue);
final Group scopeGroup = new Group(row, SWT.SHADOW_ETCHED_IN);
GridDataFactory.fillDefaults().grab(true, true).applyTo(scopeGroup);
scopeGroup.setText(Messages.getString("Search.scope")); //$NON-NLS-1$
rowLayout = new RowLayout(SWT.VERTICAL);
rowLayout.marginHeight = rowLayout.marginWidth = 3;
scopeGroup.setLayout(rowLayout);
this.allButton = new Button(scopeGroup, SWT.RADIO);
this.allButton.setText(Messages.getString("Search.allLabel")); //$NON-NLS-1$
this.allButton.setSelection(this.allValue);
this.allButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateButtons();
}
});
this.selectionButton = new Button(scopeGroup, SWT.RADIO);
this.selectionButton.setText(Messages.getString("Search.selectionLabel")); //$NON-NLS-1$
this.selectionButton.setSelection(!this.allValue);
final Group optionsGroup = new Group(row, SWT.SHADOW_ETCHED_IN);
GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(optionsGroup);
optionsGroup.setText(Messages.getString("Search.options")); //$NON-NLS-1$
optionsGroup.setLayout(new GridLayout(2, true));
this.caseSensitiveButton = new Button(optionsGroup, SWT.CHECK);
this.caseSensitiveButton.setText(Messages.getString("Search.caseSensitiveButtonLabel")); //$NON-NLS-1$
this.caseSensitiveButton.setSelection(this.caseSensitiveValue);
this.wrapSearchButton = new Button(optionsGroup, SWT.CHECK);
this.wrapSearchButton.setText(Messages.getString("Search.wrapSearchButtonLabel")); //$NON-NLS-1$
this.wrapSearchButton.setSelection(this.wrapSearchValue);
this.wholeWordButton = new Button(optionsGroup, SWT.CHECK);
this.wholeWordButton.setText(Messages.getString("Search.wholeWordButtonLabel")); //$NON-NLS-1$
this.wholeWordButton.setSelection(this.wholeWordValue);
this.wholeWordButton.setEnabled(!this.regexValue);
this.incrementalButton = new Button(optionsGroup, SWT.CHECK);
this.incrementalButton.setText(Messages.getString("Search.incrementalButtonLabel")); //$NON-NLS-1$
this.incrementalButton.setSelection(this.incrementalValue);
this.incrementalButton.setEnabled(!this.regexValue);
this.incrementalButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (SearchDialog.this.incrementalButton.getSelection()) {
resetIncrementalSelections();
}
}
});
this.regexButton = new Button(optionsGroup, SWT.CHECK);
this.regexButton.setText(Messages.getString("Search.regexButtonLabel")); //$NON-NLS-1$
this.regexButton.setSelection(this.regexValue);
this.regexButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateButtons();
}
});
this.columnFirstButton = new Button(optionsGroup, SWT.CHECK);
this.columnFirstButton.setText(Messages.getString("Search.columnFirstLabel")); //$NON-NLS-1$
this.columnFirstButton.setSelection(this.columnFirstValue);
// TODO
// includeCollapsedButton = new Button(optionsGroup, SWT.CHECK);
// includeCollapsedButton.setText(Messages.getString("Search.includeCollapsedLabel"));
// //$NON-NLS-1$
// includeCollapsedButton.setSelection(includeCollapsedValue);
return row;
}
private void doFind() {
doFindInit();
doFind0(false, this.findCombo.getText());
}
protected void doIncrementalFind() {
doFindInit();
final String text = this.findCombo.getText();
String lastText = this.selections.peek().text;
if (lastText.startsWith(text)) {
while (this.selections.size() > 1
&& this.selections.peek().text.length() > text.length()) {
this.selections.pop();
}
doSelect(this.selections.peek());
} else {
int pos;
if (text.startsWith(lastText)) {
pos = lastText.length();
} else {
pos = 0;
resetIncrementalSelections();
}
// Incremental search is performed with a loop to properly
// handle a paste, as if each character of the paste were typed
// separately, unless the search is whole word.
if (this.wholeWordValue) {
doFind0(true, text);
} else {
for (int i = pos, n = text.length(); i < n; ++i) {
doFind0(true, text.substring(0, i + 1));
}
}
}
}
private void doFindInit() {
this.statusLabel.setText(""); //$NON-NLS-1$
this.statusLabel.setForeground(null);
if (this.selectionLayer != null) {
// If the current selection is different, the user must have
// clicked a new selection, and we need to update to that.
PositionCoordinate pos = getPosition();
if (!pos.equals(this.selections.peek().pos)) {
this.selections.clear();
this.selections.push(new SelectionItem(getTextForSelection(pos), pos));
}
}
}
private void doSelect(SelectionItem selection) {
ILayerCommand command;
if (selection.pos.columnPosition != SelectionLayer.NO_SELECTION) {
command = createSelectCellCommand(selection.pos);
} else {
command = new ClearAllSelectionsCommand();
}
final ILayerCommand finalCommand = command;
BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
@Override
public void run() {
SearchDialog.this.natTable.doCommand(finalCommand);
}
});
}
private class SearchEventListener implements ILayerListener {
private PositionCoordinate pos;
@Override
public void handleLayerEvent(ILayerEvent event) {
if (!(event instanceof SearchEvent)) {
return;
}
SearchEvent searchEvent = (SearchEvent) event;
this.pos = searchEvent.getCellCoordinate();
}
}
private void doFind0(final boolean isIncremental, final String text) {
BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
@Override
public void run() {
PositionCoordinate previous =
new PositionCoordinate(SearchDialog.this.selections.peek().pos);
try {
final SearchCommand searchCommand = createSearchCommand(text, isIncremental);
final SearchEventListener searchEventListener = new SearchEventListener();
searchCommand.setSearchEventListener(searchEventListener);
SearchDialog.this.natTable.doCommand(searchCommand);
if (searchEventListener.pos == null) {
// Beep and show status if not found
SearchDialog.this.statusLabel.setText(Messages.getString("Search.textNotFound")); //$NON-NLS-1$
getShell().getDisplay().beep();
} else {
SelectionItem selection = new SelectionItem(text, searchEventListener.pos);
SearchDialog.this.selections.push(selection);
if (!isIncremental) {
resetIncrementalSelections();
}
// Beep and show status if wrapped
if (previous != null && previous.columnPosition > -1) {
int columnDelta = selection.pos.columnPosition - previous.columnPosition;
int rowDelta = selection.pos.rowPosition - previous.rowPosition;
if (!SearchDialog.this.forwardValue) {
columnDelta = -columnDelta;
rowDelta = -rowDelta;
}
int primaryDelta = SearchDialog.this.columnFirstValue ? columnDelta : rowDelta;
int secondaryDelta = SearchDialog.this.columnFirstValue ? rowDelta : columnDelta;
if (primaryDelta < 0 || !isIncremental
&& primaryDelta == 0 && secondaryDelta <= 0) {
SearchDialog.this.statusLabel.setText(Messages.getString("Search.wrappedSearch")); //$NON-NLS-1$
getShell().getDisplay().beep();
}
}
}
if (!isIncremental) {
updateFindHistory();
}
} catch (PatternSyntaxException e) {
SearchDialog.this.statusLabel.setText(e.getLocalizedMessage());
SearchDialog.this.statusLabel.setForeground(JFaceColors.getErrorText(SearchDialog.this.statusLabel.getDisplay()));
getShell().getDisplay().beep();
}
}
});
}
private PositionCoordinate getPosition() {
if (this.selectionLayer == null) {
return new PositionCoordinate(
null,
SelectionLayer.NO_SELECTION,
SelectionLayer.NO_SELECTION);
}
// The SelectionLayer keeps its anchor even if it has no selection.
// Seems wrong to me, so here I clear out the anchor.
PositionCoordinate pos = new PositionCoordinate(this.selectionLayer.getSelectionAnchor());
if (this.selectionLayer.getSelectedCellPositions().length == 0
&& pos.rowPosition != SelectionLayer.NO_SELECTION) {
this.selectionLayer.clear(false);
pos = new PositionCoordinate(this.selectionLayer.getSelectionAnchor());
}
return pos;
}
private void resetIncrementalSelections() {
SelectionItem selection = this.selections.peek();
this.selections.clear();
this.selections.push(selection);
}
private SelectCellCommand createSelectCellCommand(PositionCoordinate selection) {
SelectCellCommand selectCellCommand =
new SelectCellCommand(
selection.getLayer(),
selection.columnPosition,
selection.rowPosition,
false,
false);
selectCellCommand.setForcingEntireCellIntoViewport(true);
return selectCellCommand;
}
private SearchCommand createSearchCommand(String text, boolean isIncremental) {
this.forwardValue = this.forwardButton.getSelection();
this.allValue = this.allButton.getSelection();
this.caseSensitiveValue = this.caseSensitiveButton.getSelection();
this.wrapSearchValue = this.wrapSearchButton.getSelection();
this.wholeWordValue = this.wholeWordButton.getSelection();
this.incrementalValue = this.incrementalButton.getSelection();
this.regexValue = this.regexButton.getSelection();
// TODO
// includeCollapsedValue = includeCollapsedButton.getSelection();
this.columnFirstValue = this.columnFirstButton.getSelection();
String searchDirection = this.forwardValue ? ISearchDirection.SEARCH_FORWARD : ISearchDirection.SEARCH_BACKWARDS;
ISearchStrategy searchStrategy;
if (this.allValue) {
searchStrategy = new GridSearchStrategy(this.natTable.getConfigRegistry(), true, this.columnFirstValue);
} else {
searchStrategy = new SelectionSearchStrategy(this.natTable.getConfigRegistry(), this.columnFirstValue);
}
return new SearchCommand(
text,
this.natTable,
searchStrategy,
searchDirection,
this.wrapSearchValue,
this.caseSensitiveValue,
!this.regexValue && this.wholeWordValue,
!this.regexValue && this.allValue && isIncremental, this.regexValue,
// TODO
// includeCollapsedValue, comparator);
false,
this.comparator);
}
/**
* Called after executed find action to update the history.
*/
private void updateFindHistory() {
this.findCombo.removeModifyListener(this.findComboModifyListener);
updateHistory(this.findCombo, this.findHistory);
this.findCombo.addModifyListener(this.findComboModifyListener);
}
/**
* Updates the combo with the history.
*
* @param findCombo
* to be updated
* @param history
* to be put into the combo
*/
private static void updateHistory(Combo findCombo, List<String> history) {
String findString = findCombo.getText();
int index = history.indexOf(findString);
if (index == 0) {
return;
}
if (index != -1) {
history.remove(index);
}
history.add(0, findString);
Point selection = findCombo.getSelection();
updateCombo(findCombo, history);
findCombo.setText(findString);
findCombo.setSelection(selection);
}
/**
* Updates the given combo with the given content.
*
* @param combo
* combo to be updated
* @param content
* to be put into the combo
*/
private static void updateCombo(Combo combo, List<String> content) {
combo.removeAll();
for (int i = 0; i < content.size(); i++) {
combo.add(content.get(i).toString());
}
}
private void updateButtons() {
final boolean regex = this.regexButton.getSelection();
final boolean allMode = this.allButton.getSelection();
this.wholeWordButton.setEnabled(!regex);
this.incrementalButton.setEnabled(!regex && allMode);
}
/**
* Returns the dialog settings object used to share state between several
* find/replace dialogs.
*
* @return the dialog settings to be used
*/
private IDialogSettings getDialogSettings() {
return this.dialogSettings;
}
/*
* @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsSettings()
*/
@Override
protected IDialogSettings getDialogBoundsSettings() {
return this.dialogBounds;
}
/*
* @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsStrategy()
*/
@Override
protected int getDialogBoundsStrategy() {
return DIALOG_PERSISTLOCATION | DIALOG_PERSISTSIZE;
}
/**
* Initializes itself from the dialog settings with the same state as at the
* previous invocation.
*/
private void readConfiguration() {
IDialogSettings s = getDialogSettings();
if (s == null) {
return;
}
this.wrapSearchValue = s.get("wrap") == null || s.getBoolean("wrap"); //$NON-NLS-1$ //$NON-NLS-2$
this.caseSensitiveValue = s.getBoolean("casesensitive"); //$NON-NLS-1$
this.wholeWordValue = s.getBoolean("wholeword"); //$NON-NLS-1$
this.incrementalValue = s.getBoolean("incremental"); //$NON-NLS-1$
this.regexValue = s.getBoolean("isRegEx"); //$NON-NLS-1$
// TODO
// includeCollapsedValue = s.get("includeCollapsed") == null
// //$NON-NLS-1$
// || s.getBoolean("includeCollapsed"); //$NON-NLS-1$
this.columnFirstValue = s.getBoolean("columnFirst"); //$NON-NLS-1$
String[] findHistoryConfig = s.getArray("findhistory"); //$NON-NLS-1$
if (findHistoryConfig != null) {
this.findHistory.clear();
for (String history : findHistoryConfig) {
this.findHistory.add(history);
}
}
}
/**
* Stores its current configuration in the dialog store.
*/
private void writeConfiguration() {
IDialogSettings s = getDialogSettings();
if (s == null) {
return;
}
s.put("wrap", this.wrapSearchValue); //$NON-NLS-1$
s.put("casesensitive", this.caseSensitiveValue); //$NON-NLS-1$
s.put("wholeword", this.wholeWordValue); //$NON-NLS-1$
s.put("incremental", this.incrementalValue); //$NON-NLS-1$
s.put("isRegEx", this.regexValue); //$NON-NLS-1$
// TODO
// s.put("includeCollapsed", includeCollapsedValue); //$NON-NLS-1$
s.put("columnFirst", this.columnFirstValue); //$NON-NLS-1$
String findString = this.findCombo.getText();
if (findString.length() > 0) {
this.findHistory.add(0, findString);
}
writeHistory(this.findHistory, s, "findhistory"); //$NON-NLS-1$
}
/**
* Writes the given history into the given dialog store.
*
* @param history
* the history
* @param settings
* the dialog settings
* @param sectionName
* the section name
*/
private void writeHistory(List<String> history, IDialogSettings settings, String sectionName) {
int itemCount = history.size();
Set<String> distinctItems = new HashSet<String>(itemCount);
for (int i = 0; i < itemCount; i++) {
String item = history.get(i);
if (distinctItems.contains(item)) {
history.remove(i--);
itemCount--;
} else {
distinctItems.add(item);
}
}
while (history.size() > 8)
history.remove(8);
String[] names = new String[history.size()];
history.toArray(names);
settings.put(sectionName, names);
}
}