using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace ScintillaNet
{
public partial class FindReplaceDialog : Form
{
private List<string> _mruFind;
public List<string> MruFind
{
get
{
return _mruFind;
}
set
{
_mruFind = value;
cboFindF.DataSource = value;
cboFindR.DataSource = value;
}
}
private List<string> _mruReplace;
public List<string> MruReplace
{
get
{
return _mruReplace;
}
set
{
_mruReplace = value;
cboReplace.DataSource = value;
}
}
private int _mruMaxCount = 10;
public int MruMaxCount
{
get { return _mruMaxCount; }
set { _mruMaxCount = value; }
}
private Scintilla _scintilla;
public Scintilla Scintilla
{
get
{
return _scintilla;
}
set
{
_scintilla = value;
}
}
private Range _searchRange = null;
public FindReplaceDialog()
{
InitializeComponent();
_mruFind = new List<string>();
_mruReplace = new List<string>();
}
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
cboFindF.DataSource = cboFindR.DataSource = _mruFind;
cboReplace.DataSource = _mruReplace;
}
protected override void OnActivated(EventArgs e)
{
if (Scintilla.Selection.Length > 0)
{
chkSearchSelectionF.Enabled = true;
chkSearchSelectionR.Enabled = true;
}
else
{
chkSearchSelectionF.Enabled = false;
chkSearchSelectionR.Enabled = false;
chkSearchSelectionF.Checked = false;
chkSearchSelectionR.Checked = false;
}
// if they leave the dialog and come back any "Search Selection"
// range they might have had is invalidated
_searchRange = null;
lblStatus.Text = string.Empty;
moveFormAwayFromSelection();
base.OnActivated(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
// We'll go ahead and pass on any shortcuts back to Scintilla
// For Processing, but only under certain conditions because
// we don't want it to interfere with the operations of the
// dialog.
// One of the cool side effects of this is that the user
// can switch between the Find and Replace Tabs by using their
// configured shortcut keys from inside the window.
if (e.Control || (e.Alt && e.Shift))
{
Scintilla.FireKeyDown(e);
}
if (e.KeyCode == Keys.Escape)
Hide();
base.OnKeyDown(e);
}
private void FindReplaceDialog_FormClosing(object sender, FormClosingEventArgs e)
{
if(e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
private void rdoStandardF_CheckedChanged(object sender, EventArgs e)
{
if (rdoStandardF.Checked)
pnlStandardOptionsF.BringToFront();
else
pnlRegexpOptionsF.BringToFront();
}
private void rdoStandardR_CheckedChanged(object sender, EventArgs e)
{
if (rdoStandardR.Checked)
pnlStandardOptionsR.BringToFront();
else
pnlRegexpOptionsR.BringToFront();
}
private void tabAll_SelectedIndexChanged(object sender, EventArgs e)
{
if (tabAll.SelectedTab == tpgFind)
{
cboFindF.Text = cboFindR.Text;
rdoStandardF.Checked = rdoStandardR.Checked;
rdoRegexF.Checked = rdoRegexR.Checked;
chkWrapF.Checked = chkWrapR.Checked;
chkSearchSelectionF.Checked = chkSearchSelectionR.Checked;
chkMatchCaseF.Checked = chkMatchCaseR.Checked;
chkWholeWordF.Checked = chkWholeWordR.Checked;
chkWordStartF.Checked = chkWordStartR.Checked;
chkCompiledF.Checked = chkCompiledR.Checked;
chkCultureInvariantF.Checked = chkCultureInvariantR.Checked;
chkEcmaScriptF.Checked = chkEcmaScriptR.Checked;
chkExplicitCaptureF.Checked = chkExplicitCaptureR.Checked;
chkIgnoreCaseF.Checked = chkIgnoreCaseR.Checked;
chkIgnorePatternWhitespaceF.Checked = chkIgnorePatternWhitespaceR.Checked;
chkMultilineF.Checked = chkMultilineR.Checked;
chkRightToLeftF.Checked = chkRightToLeftR.Checked;
chkSinglelineF.Checked = chkSinglelineR.Checked;
AcceptButton = btnFindNext;
}
else
{
cboFindR.Text = cboFindF.Text;
rdoStandardR.Checked = rdoStandardF.Checked;
rdoRegexR.Checked = rdoRegexF.Checked;
chkWrapR.Checked = chkWrapF.Checked;
chkSearchSelectionR.Checked = chkSearchSelectionF.Checked;
chkMatchCaseR.Checked = chkMatchCaseF.Checked;
chkWholeWordR.Checked = chkWholeWordF.Checked;
chkWordStartR.Checked = chkWordStartF.Checked;
chkCompiledR.Checked = chkCompiledF.Checked;
chkCultureInvariantR.Checked = chkCultureInvariantF.Checked;
chkEcmaScriptR.Checked = chkEcmaScriptF.Checked;
chkExplicitCaptureR.Checked = chkExplicitCaptureF.Checked;
chkIgnoreCaseR.Checked = chkIgnoreCaseF.Checked;
chkIgnorePatternWhitespaceR.Checked = chkIgnorePatternWhitespaceF.Checked;
chkMultilineR.Checked = chkMultilineF.Checked;
chkRightToLeftR.Checked = chkRightToLeftF.Checked;
chkSinglelineR.Checked = chkSinglelineF.Checked;
AcceptButton = btnReplaceNext;
}
}
#region FindNext FR
private Range findNextF(bool searchUp)
{
Range foundRange;
if (rdoRegexF.Checked)
{
Regex rr = new Regex(cboFindF.Text, GetRegexOptions());
if (chkSearchSelectionF.Checked)
{
if (_searchRange == null)
_searchRange = Scintilla.Selection.Range;
if (searchUp)
foundRange = Scintilla.FindReplace.FindPrevious(rr, chkWrapF.Checked, _searchRange);
else
foundRange = Scintilla.FindReplace.FindNext(rr, chkWrapF.Checked, _searchRange);
}
else
{
_searchRange = null;
if (searchUp)
foundRange = Scintilla.FindReplace.FindPrevious(rr, chkWrapF.Checked);
else
foundRange = Scintilla.FindReplace.FindNext(rr, chkWrapF.Checked);
}
}
else
{
if (chkSearchSelectionF.Checked)
{
if (_searchRange == null)
_searchRange = Scintilla.Selection.Range;
if (searchUp)
foundRange = Scintilla.FindReplace.FindPrevious(cboFindF.Text, chkWrapF.Checked, GetSearchFlags(), _searchRange);
else
foundRange = Scintilla.FindReplace.FindNext(cboFindF.Text, chkWrapF.Checked, GetSearchFlags(), _searchRange);
}
else
{
_searchRange = null;
if (searchUp)
foundRange = Scintilla.FindReplace.FindPrevious(cboFindF.Text, chkWrapF.Checked, GetSearchFlags());
else
foundRange = Scintilla.FindReplace.FindNext(cboFindF.Text, chkWrapF.Checked, GetSearchFlags());
}
}
return foundRange;
}
private Range findNextR(bool searchUp, ref Regex rr)
{
Range foundRange;
if (rdoRegexR.Checked)
{
if (rr == null)
rr = new Regex(cboFindR.Text, GetRegexOptions());
if (chkSearchSelectionR.Checked)
{
if (_searchRange == null)
_searchRange = Scintilla.Selection.Range;
if (searchUp)
foundRange = Scintilla.FindReplace.FindPrevious(rr, chkWrapR.Checked, _searchRange);
else
foundRange = Scintilla.FindReplace.FindNext(rr, chkWrapR.Checked, _searchRange);
}
else
{
_searchRange = null;
if (searchUp)
foundRange = Scintilla.FindReplace.FindPrevious(rr, chkWrapR.Checked);
else
foundRange = Scintilla.FindReplace.FindNext(rr, chkWrapR.Checked);
}
}
else
{
if (chkSearchSelectionF.Checked)
{
if (_searchRange == null)
_searchRange = Scintilla.Selection.Range;
if (searchUp)
foundRange = Scintilla.FindReplace.FindPrevious(cboFindR.Text, chkWrapR.Checked, GetSearchFlags(), _searchRange);
else
foundRange = Scintilla.FindReplace.FindNext(cboFindR.Text, chkWrapR.Checked, GetSearchFlags(), _searchRange);
}
else
{
_searchRange = null;
if (searchUp)
foundRange = Scintilla.FindReplace.FindPrevious(cboFindR.Text, chkWrapF.Checked, GetSearchFlags());
else
foundRange = Scintilla.FindReplace.FindNext(cboFindR.Text, chkWrapF.Checked, GetSearchFlags());
}
}
return foundRange;
}
#endregion
public SearchFlags GetSearchFlags()
{
SearchFlags sf = SearchFlags.Empty;
if (tabAll.SelectedTab == tpgFind)
{
if (chkMatchCaseF.Checked)
sf |= SearchFlags.MatchCase;
if (chkWholeWordF.Checked)
sf |= SearchFlags.WholeWord;
if (chkWordStartF.Checked)
sf |= SearchFlags.WordStart;
}
else
{
if (chkMatchCaseR.Checked)
sf |= SearchFlags.MatchCase;
if (chkWholeWordR.Checked)
sf |= SearchFlags.WholeWord;
if (chkWordStartR.Checked)
sf |= SearchFlags.WordStart;
}
return sf;
}
public RegexOptions GetRegexOptions()
{
RegexOptions ro = RegexOptions.None;
if (tabAll.SelectedTab == tpgFind)
{
if (chkCompiledF.Checked)
ro |= RegexOptions.Compiled;
if (chkCultureInvariantF.Checked)
ro |= RegexOptions.Compiled;
if (chkEcmaScriptF.Checked)
ro |= RegexOptions.ECMAScript;
if (chkExplicitCaptureF.Checked)
ro |= RegexOptions.ExplicitCapture;
if (chkIgnoreCaseF.Checked)
ro |= RegexOptions.IgnoreCase;
if (chkIgnorePatternWhitespaceF.Checked)
ro |= RegexOptions.IgnorePatternWhitespace;
if (chkMultilineF.Checked)
ro |= RegexOptions.Multiline;
if (chkRightToLeftF.Checked)
ro |= RegexOptions.RightToLeft;
if (chkSinglelineF.Checked)
ro |= RegexOptions.Singleline;
}
else
{
if (chkCompiledR.Checked)
ro |= RegexOptions.Compiled;
if (chkCultureInvariantR.Checked)
ro |= RegexOptions.Compiled;
if (chkEcmaScriptR.Checked)
ro |= RegexOptions.ECMAScript;
if (chkExplicitCaptureR.Checked)
ro |= RegexOptions.ExplicitCapture;
if (chkIgnoreCaseR.Checked)
ro |= RegexOptions.IgnoreCase;
if (chkIgnorePatternWhitespaceR.Checked)
ro |= RegexOptions.IgnorePatternWhitespace;
if (chkMultilineR.Checked)
ro |= RegexOptions.Multiline;
if (chkRightToLeftR.Checked)
ro |= RegexOptions.RightToLeft;
if (chkSinglelineR.Checked)
ro |= RegexOptions.Singleline;
}
return ro;
}
private void chkEcmaScript_CheckedChanged(object sender, EventArgs e)
{
if (((CheckBox)sender).Checked)
{
chkExplicitCaptureF.Checked = false;
chkExplicitCaptureR.Checked = false;
chkExplicitCaptureF.Enabled = false;
chkExplicitCaptureR.Enabled = false;
chkIgnorePatternWhitespaceF.Checked = false;
chkIgnorePatternWhitespaceR.Checked = false;
chkIgnorePatternWhitespaceF.Enabled = false;
chkIgnorePatternWhitespaceR.Enabled = false;
chkRightToLeftF.Checked = false;
chkRightToLeftR.Checked = false;
chkRightToLeftF.Enabled = false;
chkRightToLeftR.Enabled = false;
chkSinglelineF.Checked = false;
chkSinglelineR.Checked = false;
chkSinglelineF.Enabled = false;
chkSinglelineR.Enabled = false;
}
else
{
chkExplicitCaptureF.Enabled = true;
chkIgnorePatternWhitespaceF.Enabled = true;
chkRightToLeftF.Enabled = true;
chkSinglelineF.Enabled = true;
chkExplicitCaptureR.Enabled = true;
chkIgnorePatternWhitespaceR.Enabled = true;
chkRightToLeftR.Enabled = true;
chkSinglelineR.Enabled = true;
}
}
private void addFindMru()
{
string find = cboFindF.Text;
_mruFind.Remove(find);
_mruFind.Insert(0, find);
if (_mruFind.Count > _mruMaxCount)
_mruFind.RemoveAt(_mruFind.Count - 1);
cboFindF.DataSource = cboFindR.DataSource = _mruFind;
}
private void addReplacMru()
{
string find = cboFindR.Text;
_mruFind.Remove(find);
_mruFind.Insert(0, find);
if (_mruFind.Count > _mruMaxCount)
_mruFind.RemoveAt(_mruFind.Count - 1);
string replace = cboReplace.Text;
if (replace != string.Empty)
{
_mruReplace.Remove(replace);
_mruReplace.Insert(0, replace);
if (_mruReplace.Count > _mruMaxCount)
_mruReplace.RemoveAt(_mruReplace.Count - 1);
}
cboFindF.DataSource = cboFindR.DataSource = _mruFind;
cboReplace.DataSource = _mruReplace;
}
private void btnFindAll_Click(object sender, EventArgs e)
{
if (cboFindF.Text == string.Empty)
return;
addFindMru();
lblStatus.Text = string.Empty;
List<Range> foundRanges = null;
if (rdoRegexF.Checked)
{
Regex rr = null;
try
{
rr = new Regex(cboFindF.Text, GetRegexOptions());
}
catch (ArgumentException ex)
{
lblStatus.Text = "Error in Regular Expression: " + ex.Message;
return;
}
if (chkSearchSelectionF.Checked)
{
if (_searchRange == null)
{
_searchRange = Scintilla.Selection.Range;
}
foundRanges = Scintilla.FindReplace.FindAll(_searchRange, rr);
}
else
{
_searchRange = null;
foundRanges = Scintilla.FindReplace.FindAll(rr);
}
}
else
{
if (chkSearchSelectionF.Checked)
{
if (_searchRange == null)
_searchRange = Scintilla.Selection.Range;
foundRanges = Scintilla.FindReplace.FindAll(_searchRange, cboFindF.Text, GetSearchFlags());
}
else
{
_searchRange = null;
foundRanges = Scintilla.FindReplace.FindAll(cboFindF.Text, GetSearchFlags());
}
}
lblStatus.Text = "Total found: " + foundRanges.Count.ToString();
btnClear_Click(null, null);
if (chkMarkLine.Checked)
Scintilla.FindReplace.MarkAll(foundRanges);
if (chkHighlightMatches.Checked)
Scintilla.FindReplace.HighlightAll(foundRanges);
}
private void btnClear_Click(object sender, EventArgs e)
{
Scintilla.Markers.DeleteAll(Scintilla.FindReplace.Marker);
Scintilla.FindReplace.ClearAllHighlights();
}
private void btnReplacePrevious_Click(object sender, EventArgs e)
{
if (cboFindR.Text == string.Empty)
return;
addReplacMru();
lblStatus.Text = string.Empty;
Range nextRange = null;
try
{
nextRange = replaceNext(true);
}
catch (ArgumentException ex)
{
lblStatus.Text = "Error in Regular Expression: " + ex.Message;
return;
}
if (nextRange == null)
{
lblStatus.Text = "Match could not be found";
}
else
{
if (nextRange.Start > Scintilla.Caret.Anchor)
{
if (chkSearchSelectionR.Checked)
lblStatus.Text = "Search match wrapped to the begining of the selection";
else
lblStatus.Text = "Search match wrapped to the begining of the document";
}
nextRange.Select();
moveFormAwayFromSelection();
}
}
private Range replaceNext(bool searchUp)
{
Regex rr = null;
Range selRange = Scintilla.Selection.Range;
// We only do the actual replacement if the current selection exactly
// matches the find.
if (selRange.Length > 0)
{
if (rdoRegexR.Checked)
{
rr = new Regex(cboFindR.Text, GetRegexOptions());
string selRangeText = selRange.Text;
if (selRange.Equals(Scintilla.FindReplace.Find(selRange, rr, false)))
{
// If searching up we do the replacement using the range object.
// Otherwise we use the selection object. The reason being if
// we use the range the caret is positioned before the replaced
// text. Conversely if we use the selection object the caret will
// be positioned after the replaced text. This is very important
// becuase we don't want the new text to be potentially matched
// in the next search.
if (searchUp)
selRange.Text = rr.Replace(selRangeText, cboReplace.Text);
else
Scintilla.Selection.Text = rr.Replace(selRangeText, cboReplace.Text);
}
}
else
{
if (selRange.Equals(Scintilla.FindReplace.Find(selRange, cboFindR.Text, false)))
{
if (searchUp)
selRange.Text = cboReplace.Text;
else
Scintilla.Selection.Text = cboReplace.Text;
}
}
}
return findNextR(searchUp, ref rr);
}
private void btnReplaceNext_Click(object sender, EventArgs e)
{
if (cboFindR.Text == string.Empty)
return;
addReplacMru();
lblStatus.Text = string.Empty;
Range nextRange = null;
try
{
nextRange = replaceNext(false);
}
catch (ArgumentException ex)
{
lblStatus.Text = "Error in Regular Expression: " + ex.Message;
return;
}
if (nextRange == null)
{
lblStatus.Text = "Match could not be found";
}
else
{
if (nextRange.Start < Scintilla.Caret.Anchor)
{
if (chkSearchSelectionR.Checked)
lblStatus.Text = "Search match wrapped to the begining of the selection";
else
lblStatus.Text = "Search match wrapped to the begining of the document";
}
nextRange.Select();
moveFormAwayFromSelection();
}
}
private void btnReplaceAll_Click(object sender, EventArgs e)
{
if (cboFindR.Text == string.Empty)
return;
lblStatus.Text = string.Empty;
List<Range> foundRanges = null;
if (rdoRegexR.Checked)
{
Regex rr = null;
try
{
rr = new Regex(cboFindR.Text, GetRegexOptions());
}
catch (ArgumentException ex)
{
lblStatus.Text = "Error in Regular Expression: " + ex.Message;
return;
}
if (chkSearchSelectionR.Checked)
{
if (_searchRange == null)
{
_searchRange = Scintilla.Selection.Range;
}
foundRanges = Scintilla.FindReplace.ReplaceAll(_searchRange, rr, cboReplace.Text);
}
else
{
_searchRange = null;
foundRanges = Scintilla.FindReplace.ReplaceAll(rr, cboReplace.Text);
}
}
else
{
if (chkSearchSelectionR.Checked)
{
if (_searchRange == null)
_searchRange = Scintilla.Selection.Range;
foundRanges = Scintilla.FindReplace.ReplaceAll(_searchRange, cboFindR.Text, cboReplace.Text, GetSearchFlags());
}
else
{
_searchRange = null;
foundRanges = Scintilla.FindReplace.ReplaceAll(cboFindR.Text, cboReplace.Text, GetSearchFlags());
}
}
lblStatus.Text = "Total Replaced: " + foundRanges.Count.ToString();
}
private void btnFindNext_Click(object sender, EventArgs e)
{
FindNext();
}
public void FindNext()
{
if (cboFindF.Text == string.Empty)
return;
addFindMru();
lblStatus.Text = string.Empty;
Range foundRange = null;
try
{
foundRange = findNextF(false);
}
catch (ArgumentException ex)
{
lblStatus.Text = "Error in Regular Expression: " + ex.Message;
return;
}
if (foundRange == null)
{
lblStatus.Text = "Match could not be found";
}
else
{
if (foundRange.Start < Scintilla.Caret.Anchor)
{
if (chkSearchSelectionF.Checked)
lblStatus.Text = "Search match wrapped to the begining of the selection";
else
lblStatus.Text = "Search match wrapped to the begining of the document";
}
foundRange.Select();
moveFormAwayFromSelection();
}
}
private void btnFindPrevious_Click(object sender, EventArgs e)
{
FindPrevious();
}
public void FindPrevious()
{
if (cboFindF.Text == string.Empty)
return;
addFindMru();
lblStatus.Text = string.Empty;
Range foundRange = null;
try
{
foundRange = findNextF(true);
}
catch (ArgumentException ex)
{
lblStatus.Text = "Error in Regular Expression: " + ex.Message;
return;
}
if (foundRange == null)
{
lblStatus.Text = "Match could not be found";
}
else
{
if (foundRange.Start > Scintilla.Caret.Position)
{
if (chkSearchSelectionF.Checked)
lblStatus.Text = "Search match wrapped to the end of the selection";
else
lblStatus.Text = "Search match wrapped to the end of the document";
}
foundRange.Select();
moveFormAwayFromSelection();
}
}
public void moveFormAwayFromSelection()
{
if (!Visible)
return;
int pos = Scintilla.Caret.Position;
int x = Scintilla.PointXFromPosition(pos);
int y = Scintilla.PointYFromPosition(pos);
Point cursorPoint = Scintilla.PointToScreen(new Point(x, y));
Rectangle r = new Rectangle(Location, Size);
if (r.Contains(cursorPoint))
{
Point newLocation;
if (cursorPoint.Y < (Screen.PrimaryScreen.Bounds.Height / 2))
{
// Top half of the screen
newLocation = Scintilla.PointToClient(
new Point(Location.X, cursorPoint.Y + Scintilla.Lines.Current.Height*2)
);
}
else
{
// Bottom half of the screen
newLocation = Scintilla.PointToClient(
new Point(Location.X, cursorPoint.Y - Height - (Scintilla.Lines.Current.Height * 2))
);
}
newLocation = Scintilla.PointToScreen(newLocation);
Location = newLocation;
}
}
}
}