using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; using Terminal.Gui; using static UICatalog.Scenarios.DynamicMenuBar; namespace UICatalog.Scenarios; [ScenarioMetadata ("Editor", "A Text Editor using the TextView control.")] [ScenarioCategory ("Controls")] [ScenarioCategory ("Dialogs")] [ScenarioCategory ("Text and Formatting")] [ScenarioCategory ("Top Level Windows")] [ScenarioCategory ("Files and IO")] [ScenarioCategory ("TextView")] [ScenarioCategory ("Menus")] public class Editor : Scenario { private Window _appWindow; private List _cultureInfos; private string _fileName = "demo.txt"; private bool _forceMinimumPosToZero = true; private bool _matchCase; private bool _matchWholeWord; private MenuItem _miForceMinimumPosToZero; private byte [] _originalText; private bool _saved = true; private ScrollBarView _scrollBar; private TabView _tabView; private string _textToFind; private string _textToReplace; private TextView _textView; private FindReplaceWindow _findReplaceWindow; public override void Main () { // Init Application.Init (); // Setup - Create a top-level application window and configure it. _appWindow = new () { //Title = GetQuitKeyAndName (), Title = _fileName ?? "Untitled", BorderStyle = LineStyle.None }; _cultureInfos = Application.SupportedCultures; _textView = new () { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill (1), }; CreateDemoFile (_fileName); LoadFile (); _appWindow.Add (_textView); var menu = new MenuBar { Menus = [ new ( "_File", new MenuItem [] { new ("_New", "", () => New ()), new ("_Open", "", () => Open ()), new ("_Save", "", () => Save ()), new ("_Save As", "", () => SaveAs ()), new ("_Close", "", () => CloseFile ()), null, new ("_Quit", "", () => Quit ()) } ), new ( "_Edit", new MenuItem [] { new ( "_Copy", "", () => Copy (), null, null, KeyCode.CtrlMask | KeyCode.C ), new ( "C_ut", "", () => Cut (), null, null, KeyCode.CtrlMask | KeyCode.W ), new ( "_Paste", "", () => Paste (), null, null, KeyCode.CtrlMask | KeyCode.Y ), null, new ( "_Find", "", () => Find (), null, null, KeyCode.CtrlMask | KeyCode.S ), new ( "Find _Next", "", () => FindNext (), null, null, KeyCode.CtrlMask | KeyCode.ShiftMask | KeyCode.S ), new ( "Find P_revious", "", () => FindPrevious (), null, null, KeyCode.CtrlMask | KeyCode.ShiftMask | KeyCode.AltMask | KeyCode.S ), new ( "_Replace", "", () => Replace (), null, null, KeyCode.CtrlMask | KeyCode.R ), new ( "Replace Ne_xt", "", () => ReplaceNext (), null, null, KeyCode.CtrlMask | KeyCode.ShiftMask | KeyCode.R ), new ( "Replace Pre_vious", "", () => ReplacePrevious (), null, null, KeyCode.CtrlMask | KeyCode.ShiftMask | KeyCode.AltMask | KeyCode.R ), new ( "Replace _All", "", () => ReplaceAll (), null, null, KeyCode.CtrlMask | KeyCode.ShiftMask | KeyCode.AltMask | KeyCode.A ), null, new ( "_Select All", "", () => SelectAll (), null, null, KeyCode.CtrlMask | KeyCode.T ) } ), new ("_ScrollBarView", CreateKeepChecked ()), new ("_Cursor", CreateCursorRadio ()), new ( "Forma_t", new [] { CreateWrapChecked (), CreateAutocomplete (), CreateAllowsTabChecked (), CreateReadOnlyChecked () } ), new ( "_Responder", new [] { CreateCanFocusChecked (), CreateEnabledChecked (), CreateVisibleChecked () } ), new ( "Conte_xtMenu", new [] { _miForceMinimumPosToZero = new ( "ForceMinimumPosTo_Zero", "", () => { _miForceMinimumPosToZero.Checked = _forceMinimumPosToZero = !_forceMinimumPosToZero; _textView.ContextMenu.ForceMinimumPosToZero = _forceMinimumPosToZero; } ) { CheckType = MenuItemCheckStyle.Checked, Checked = _forceMinimumPosToZero }, new MenuBarItem ("_Languages", GetSupportedCultures ()) } ) ] }; _appWindow.Add (menu); var siCursorPosition = new Shortcut (KeyCode.Null, "", null); var statusBar = new StatusBar ( new [] { new (Application.QuitKey, $"Quit", Quit), new (Key.F2, "Open", Open), new (Key.F3, "Save", () => Save ()), new (Key.F4, "Save As", () => SaveAs ()), new (Key.Empty, $"OS Clipboard IsSupported : {Clipboard.IsSupported}", null), siCursorPosition, } ) { AlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast }; _textView.UnwrappedCursorPosition += (s, e) => { siCursorPosition.Title = $"Ln {e.Point.Y + 1}, Col {e.Point.X + 1}"; }; _appWindow.Add (statusBar); _scrollBar = new (_textView, true); _scrollBar.ChangedPosition += (s, e) => { _textView.TopRow = _scrollBar.Position; if (_textView.TopRow != _scrollBar.Position) { _scrollBar.Position = _textView.TopRow; } _textView.SetNeedsDisplay (); }; _scrollBar.OtherScrollBarView.ChangedPosition += (s, e) => { _textView.LeftColumn = _scrollBar.OtherScrollBarView.Position; if (_textView.LeftColumn != _scrollBar.OtherScrollBarView.Position) { _scrollBar.OtherScrollBarView.Position = _textView.LeftColumn; } _textView.SetNeedsDisplay (); }; _textView.DrawContent += (s, e) => { _scrollBar.Size = _textView.Lines; _scrollBar.Position = _textView.TopRow; if (_scrollBar.OtherScrollBarView != null) { _scrollBar.OtherScrollBarView.Size = _textView.Maxlength; _scrollBar.OtherScrollBarView.Position = _textView.LeftColumn; } _scrollBar.LayoutSubviews (); _scrollBar.Refresh (); }; _appWindow.Closed += (s, e) => Thread.CurrentThread.CurrentUICulture = new ("en-US"); CreateFindReplace (); // Run - Start the application. Application.Run (_appWindow); _appWindow.Dispose (); // Shutdown - Calling Application.Shutdown is required. Application.Shutdown (); } private bool CanCloseFile () { if (_textView.Text == Encoding.Unicode.GetString (_originalText)) { //System.Diagnostics.Debug.Assert (!_textView.IsDirty); return true; } Debug.Assert (_textView.IsDirty); int r = MessageBox.ErrorQuery ( "Save File", $"Do you want save changes in {_appWindow.Title}?", "Yes", "No", "Cancel" ); if (r == 0) { return Save (); } if (r == 1) { return true; } return false; } private void CloseFile () { if (!CanCloseFile ()) { return; } try { _textView.CloseFile (); New (false); } catch (Exception ex) { MessageBox.ErrorQuery ("Error", ex.Message, "Ok"); } } private void ContinueFind (bool next = true, bool replace = false) { if (!replace && string.IsNullOrEmpty (_textToFind)) { Find (); return; } if (replace && (string.IsNullOrEmpty (_textToFind) || (_findReplaceWindow == null && string.IsNullOrEmpty (_textToReplace)))) { Replace (); return; } bool found; bool gaveFullTurn; if (next) { if (!replace) { found = _textView.FindNextText ( _textToFind, out gaveFullTurn, _matchCase, _matchWholeWord ); } else { found = _textView.FindNextText ( _textToFind, out gaveFullTurn, _matchCase, _matchWholeWord, _textToReplace, true ); } } else { if (!replace) { found = _textView.FindPreviousText ( _textToFind, out gaveFullTurn, _matchCase, _matchWholeWord ); } else { found = _textView.FindPreviousText ( _textToFind, out gaveFullTurn, _matchCase, _matchWholeWord, _textToReplace, true ); } } if (!found) { MessageBox.Query ("Find", $"The following specified text was not found: '{_textToFind}'", "Ok"); } else if (gaveFullTurn) { MessageBox.Query ( "Find", $"No more occurrences were found for the following specified text: '{_textToFind}'", "Ok" ); } } private void Copy () { if (_textView != null) { _textView.Copy (); } } private MenuItem CreateAllowsTabChecked () { var item = new MenuItem { Title = "Allows Tab" }; item.CheckType |= MenuItemCheckStyle.Checked; item.Checked = _textView.AllowsTab; item.Action += () => { _textView.AllowsTab = (bool)(item.Checked = !item.Checked); }; return item; } private MenuItem CreateAutocomplete () { var singleWordGenerator = new SingleWordSuggestionGenerator (); _textView.Autocomplete.SuggestionGenerator = singleWordGenerator; var auto = new MenuItem (); auto.Title = "Autocomplete"; auto.CheckType |= MenuItemCheckStyle.Checked; auto.Checked = false; auto.Action += () => { if ((bool)(auto.Checked = !auto.Checked)) { // setup autocomplete with all words currently in the editor singleWordGenerator.AllSuggestions = Regex.Matches (_textView.Text, "\\w+") .Select (s => s.Value) .Distinct () .ToList (); } else { singleWordGenerator.AllSuggestions.Clear (); } }; return auto; } private MenuItem CreateCanFocusChecked () { var item = new MenuItem { Title = "CanFocus" }; item.CheckType |= MenuItemCheckStyle.Checked; item.Checked = _textView.CanFocus; item.Action += () => { _textView.CanFocus = (bool)(item.Checked = !item.Checked); if (_textView.CanFocus) { _textView.SetFocus (); } }; return item; } private MenuItem [] CreateCursorRadio () { List menuItems = new (); menuItems.Add ( new ("_Invisible", "", () => SetCursor (CursorVisibility.Invisible)) { CheckType = MenuItemCheckStyle.Radio, Checked = _textView.CursorVisibility == CursorVisibility.Invisible } ); menuItems.Add ( new ("_Box", "", () => SetCursor (CursorVisibility.Box)) { CheckType = MenuItemCheckStyle.Radio, Checked = _textView.CursorVisibility == CursorVisibility.Box } ); menuItems.Add ( new ("_Underline", "", () => SetCursor (CursorVisibility.Underline)) { CheckType = MenuItemCheckStyle.Radio, Checked = _textView.CursorVisibility == CursorVisibility.Underline } ); menuItems.Add (new ("", "", () => { }, () => false)); menuItems.Add (new ("xTerm :", "", () => { }, () => false)); menuItems.Add (new ("", "", () => { }, () => false)); menuItems.Add ( new (" _Default", "", () => SetCursor (CursorVisibility.Default)) { CheckType = MenuItemCheckStyle.Radio, Checked = _textView.CursorVisibility == CursorVisibility.Default } ); menuItems.Add ( new (" _Vertical", "", () => SetCursor (CursorVisibility.Vertical)) { CheckType = MenuItemCheckStyle.Radio, Checked = _textView.CursorVisibility == CursorVisibility.Vertical } ); menuItems.Add ( new (" V_ertical Fix", "", () => SetCursor (CursorVisibility.VerticalFix)) { CheckType = MenuItemCheckStyle.Radio, Checked = _textView.CursorVisibility == CursorVisibility.VerticalFix } ); menuItems.Add ( new (" B_ox Fix", "", () => SetCursor (CursorVisibility.BoxFix)) { CheckType = MenuItemCheckStyle.Radio, Checked = _textView.CursorVisibility == CursorVisibility.BoxFix } ); menuItems.Add ( new (" U_nderline Fix", "", () => SetCursor (CursorVisibility.UnderlineFix)) { CheckType = MenuItemCheckStyle.Radio, Checked = _textView.CursorVisibility == CursorVisibility.UnderlineFix } ); void SetCursor (CursorVisibility visibility) { _textView.CursorVisibility = visibility; var title = ""; switch (visibility) { case CursorVisibility.Default: title = " _Default"; break; case CursorVisibility.Invisible: title = "_Invisible"; break; case CursorVisibility.Underline: title = "_Underline"; break; case CursorVisibility.UnderlineFix: title = " U_nderline Fix"; break; case CursorVisibility.Vertical: title = " _Vertical"; break; case CursorVisibility.VerticalFix: title = " V_ertical Fix"; break; case CursorVisibility.Box: title = "_Box"; break; case CursorVisibility.BoxFix: title = " B_ox Fix"; break; } foreach (MenuItem menuItem in menuItems) { menuItem.Checked = menuItem.Title.Equals (title) && visibility == _textView.CursorVisibility; } } return menuItems.ToArray (); } private void CreateDemoFile (string fileName) { var sb = new StringBuilder (); // FIXED: BUGBUG: #279 TextView does not know how to deal with \r\n, only \r sb.Append ("Hello world.\n"); sb.Append ("This is a test of the Emergency Broadcast System.\n"); for (var i = 0; i < 30; i++) { sb.Append ( $"{i} - This is a test with a very long line and many lines to test the ScrollViewBar against the TextView. - {i}\n" ); } StreamWriter sw = File.CreateText (fileName); sw.Write (sb.ToString ()); sw.Close (); } private MenuItem CreateEnabledChecked () { var item = new MenuItem { Title = "Enabled" }; item.CheckType |= MenuItemCheckStyle.Checked; item.Checked = _textView.Enabled; item.Action += () => { _textView.Enabled = (bool)(item.Checked = !item.Checked); if (_textView.Enabled) { _textView.SetFocus (); } }; return item; } private class FindReplaceWindow : Window { private TextView _textView; public FindReplaceWindow (TextView textView) { Title = "Find and Replace"; _textView = textView; X = Pos.AnchorEnd () - 1; Y = 2; Width = 57; Height = 11; Arrangement = ViewArrangement.Movable; KeyBindings.Add (Key.Esc, KeyBindingScope.Focused, Command.Cancel); AddCommand (Command.Cancel, () => { Visible = false; return true; }); VisibleChanged += FindReplaceWindow_VisibleChanged; Initialized += FindReplaceWindow_Initialized; //var btnCancel = new Button //{ // X = Pos.AnchorEnd (), // Y = Pos.AnchorEnd (), // Text = "Cancel" //}; //btnCancel.Accept += (s, e) => { Visible = false; }; //Add (btnCancel); } private void FindReplaceWindow_VisibleChanged (object sender, EventArgs e) { if (Visible == false) { _textView.SetFocus (); } else { FocusFirst (null); } } private void FindReplaceWindow_Initialized (object sender, EventArgs e) { Border.LineStyle = LineStyle.Dashed; Border.Thickness = new (0, 1, 0, 0); } } private void ShowFindReplace (bool isFind = true) { _findReplaceWindow.Visible = true; _findReplaceWindow.SuperView.BringSubviewToFront (_findReplaceWindow); _tabView.SetFocus (); _tabView.SelectedTab = isFind ? _tabView.Tabs.ToArray () [0] : _tabView.Tabs.ToArray () [1]; _tabView.SelectedTab.View.FocusFirst (null); } private void CreateFindReplace () { _findReplaceWindow = new (_textView); _tabView = new () { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill (0) }; _tabView.AddTab (new () { DisplayText = "Find", View = CreateFindTab () }, true); _tabView.AddTab (new () { DisplayText = "Replace", View = CreateReplaceTab () }, false); _tabView.SelectedTabChanged += (s, e) => _tabView.SelectedTab.View.FocusFirst (null); _findReplaceWindow.Add (_tabView); _tabView.SelectedTab.View.FocusLast (null); // Hack to get the first tab to be focused _findReplaceWindow.Visible = false; _appWindow.Add (_findReplaceWindow); } private MenuItem [] CreateKeepChecked () { var item = new MenuItem (); item.Title = "Keep Content Always In Viewport"; item.CheckType |= MenuItemCheckStyle.Checked; item.Checked = true; item.Action += () => _scrollBar.KeepContentAlwaysInViewport = (bool)(item.Checked = !item.Checked); return new [] { item }; } private MenuItem CreateReadOnlyChecked () { var item = new MenuItem { Title = "Read Only" }; item.CheckType |= MenuItemCheckStyle.Checked; item.Checked = _textView.ReadOnly; item.Action += () => _textView.ReadOnly = (bool)(item.Checked = !item.Checked); return item; } private MenuItem CreateVisibleChecked () { var item = new MenuItem { Title = "Visible" }; item.CheckType |= MenuItemCheckStyle.Checked; item.Checked = _textView.Visible; item.Action += () => { _textView.Visible = (bool)(item.Checked = !item.Checked); if (_textView.Visible) { _textView.SetFocus (); } }; return item; } private MenuItem CreateWrapChecked () { var item = new MenuItem { Title = "Word Wrap" }; item.CheckType |= MenuItemCheckStyle.Checked; item.Checked = _textView.WordWrap; item.Action += () => { _textView.WordWrap = (bool)(item.Checked = !item.Checked); if (_textView.WordWrap) { _scrollBar.OtherScrollBarView.ShowScrollIndicator = false; } }; return item; } private void Cut () { if (_textView != null) { _textView.Cut (); } } private void Find () { ShowFindReplace (true); } private void FindNext () { ContinueFind (); } private void FindPrevious () { ContinueFind (false); } private View CreateFindTab () { var d = new View () { Width = Dim.Fill (), Height = Dim.Fill () }; int lblWidth = "Replace:".Length; var label = new Label { Width = lblWidth, TextAlignment = Alignment.End, Text = "Find:" }; d.Add (label); SetFindText (); var txtToFind = new TextField { X = Pos.Right (label) + 1, Y = Pos.Top (label), Width = Dim.Fill (1), Text = _textToFind }; txtToFind.Enter += (s, e) => txtToFind.Text = _textToFind; d.Add (txtToFind); var btnFindNext = new Button { X = Pos.Align (Alignment.Center), Y = Pos.AnchorEnd (), Enabled = !string.IsNullOrEmpty (txtToFind.Text), IsDefault = true, Text = "Find _Next" }; btnFindNext.Accept += (s, e) => FindNext (); d.Add (btnFindNext); var btnFindPrevious = new Button { X = Pos.Align (Alignment.Center), Y = Pos.AnchorEnd (), Enabled = !string.IsNullOrEmpty (txtToFind.Text), Text = "Find _Previous" }; btnFindPrevious.Accept += (s, e) => FindPrevious (); d.Add (btnFindPrevious); txtToFind.TextChanged += (s, e) => { _textToFind = txtToFind.Text; _textView.FindTextChanged (); btnFindNext.Enabled = !string.IsNullOrEmpty (txtToFind.Text); btnFindPrevious.Enabled = !string.IsNullOrEmpty (txtToFind.Text); }; var ckbMatchCase = new CheckBox { X = 0, Y = Pos.Top (txtToFind) + 2, State = _matchCase ? CheckState.Checked : CheckState.UnChecked, Text = "Match c_ase" }; ckbMatchCase.Toggle += (s, e) => _matchCase = e.NewValue == CheckState.Checked; d.Add (ckbMatchCase); var ckbMatchWholeWord = new CheckBox { X = 0, Y = Pos.Top (ckbMatchCase) + 1, State = _matchWholeWord ? CheckState.Checked : CheckState.UnChecked, Text = "Match _whole word" }; ckbMatchWholeWord.Toggle += (s, e) => _matchWholeWord = e.NewValue == CheckState.Checked; d.Add (ckbMatchWholeWord); return d; } private MenuItem [] GetSupportedCultures () { List supportedCultures = new (); int index = -1; foreach (CultureInfo c in _cultureInfos) { var culture = new MenuItem { CheckType = MenuItemCheckStyle.Checked }; if (index == -1) { culture.Title = "_English"; culture.Help = "en-US"; culture.Checked = Thread.CurrentThread.CurrentUICulture.Name == "en-US"; CreateAction (supportedCultures, culture); supportedCultures.Add (culture); index++; culture = new () { CheckType = MenuItemCheckStyle.Checked }; } culture.Title = $"_{c.Parent.EnglishName}"; culture.Help = c.Name; culture.Checked = Thread.CurrentThread.CurrentUICulture.Name == c.Name; CreateAction (supportedCultures, culture); supportedCultures.Add (culture); } return supportedCultures.ToArray (); void CreateAction (List supportedCultures, MenuItem culture) { culture.Action += () => { Thread.CurrentThread.CurrentUICulture = new (culture.Help); culture.Checked = true; foreach (MenuItem item in supportedCultures) { item.Checked = item.Help == Thread.CurrentThread.CurrentUICulture.Name; } }; } } private void LoadFile () { if (_fileName != null) { // FIXED: BUGBUG: #452 TextView.LoadFile keeps file open and provides no way of closing it _textView.Load (_fileName); //_textView.Text = System.IO.File.ReadAllText (_fileName); _originalText = Encoding.Unicode.GetBytes (_textView.Text); _appWindow.Title = _fileName; _saved = true; } } private void New (bool checkChanges = true) { if (checkChanges && !CanCloseFile ()) { return; } _appWindow.Title = "Untitled.txt"; _fileName = null; _originalText = new MemoryStream ().ToArray (); _textView.Text = Encoding.Unicode.GetString (_originalText); } private void Open () { if (!CanCloseFile ()) { return; } List aTypes = new () { new AllowedType ( "Text", ".txt;.bin;.xml;.json", ".txt", ".bin", ".xml", ".json" ), new AllowedTypeAny () }; var d = new OpenDialog { Title = "Open", AllowedTypes = aTypes, AllowsMultipleSelection = false }; Application.Run (d); if (!d.Canceled && d.FilePaths.Count > 0) { _fileName = d.FilePaths [0]; LoadFile (); } d.Dispose (); } private void Paste () { if (_textView != null) { _textView.Paste (); } } private void Quit () { if (!CanCloseFile ()) { return; } Application.RequestStop (); } private void Replace () { ShowFindReplace (false); } private void ReplaceAll () { if (string.IsNullOrEmpty (_textToFind) || (string.IsNullOrEmpty (_textToReplace) && _findReplaceWindow == null)) { Replace (); return; } if (_textView.ReplaceAllText (_textToFind, _matchCase, _matchWholeWord, _textToReplace)) { MessageBox.Query ( "Replace All", $"All occurrences were replaced for the following specified text: '{_textToReplace}'", "Ok" ); } else { MessageBox.Query ( "Replace All", $"None of the following specified text was found: '{_textToFind}'", "Ok" ); } } private void ReplaceNext () { ContinueFind (true, true); } private void ReplacePrevious () { ContinueFind (false, true); } private View CreateReplaceTab () { var d = new View () { Width = Dim.Fill (), Height = Dim.Fill () }; int lblWidth = "Replace:".Length; var label = new Label { Width = lblWidth, TextAlignment = Alignment.End, Text = "Find:" }; d.Add (label); SetFindText (); var txtToFind = new TextField { X = Pos.Right (label) + 1, Y = Pos.Top (label), Width = Dim.Fill (1), Text = _textToFind }; txtToFind.Enter += (s, e) => txtToFind.Text = _textToFind; d.Add (txtToFind); var btnFindNext = new Button { X = Pos.Align (Alignment.Center), Y = Pos.AnchorEnd (), Enabled = !string.IsNullOrEmpty (txtToFind.Text), IsDefault = true, Text = "Replace _Next" }; btnFindNext.Accept += (s, e) => ReplaceNext (); d.Add (btnFindNext); label = new () { X = Pos.Left (label), Y = Pos.Top (label) + 1, Text = "Replace:" }; d.Add (label); SetFindText (); var txtToReplace = new TextField { X = Pos.Right (label) + 1, Y = Pos.Top (label), Width = Dim.Fill (1), Text = _textToReplace }; txtToReplace.TextChanged += (s, e) => _textToReplace = txtToReplace.Text; d.Add (txtToReplace); var btnFindPrevious = new Button { X = Pos.Align (Alignment.Center), Y = Pos.AnchorEnd (), Enabled = !string.IsNullOrEmpty (txtToFind.Text), Text = "Replace _Previous" }; btnFindPrevious.Accept += (s, e) => ReplacePrevious (); d.Add (btnFindPrevious); var btnReplaceAll = new Button { X = Pos.Align (Alignment.Center), Y = Pos.AnchorEnd (), Enabled = !string.IsNullOrEmpty (txtToFind.Text), Text = "Replace _All" }; btnReplaceAll.Accept += (s, e) => ReplaceAll (); d.Add (btnReplaceAll); txtToFind.TextChanged += (s, e) => { _textToFind = txtToFind.Text; _textView.FindTextChanged (); btnFindNext.Enabled = !string.IsNullOrEmpty (txtToFind.Text); btnFindPrevious.Enabled = !string.IsNullOrEmpty (txtToFind.Text); btnReplaceAll.Enabled = !string.IsNullOrEmpty (txtToFind.Text); }; var ckbMatchCase = new CheckBox { X = 0, Y = Pos.Top (txtToFind) + 2, State = _matchCase ? CheckState.Checked : CheckState.UnChecked, Text = "Match c_ase" }; ckbMatchCase.Toggle += (s, e) => _matchCase = e.NewValue == CheckState.Checked; d.Add (ckbMatchCase); var ckbMatchWholeWord = new CheckBox { X = 0, Y = Pos.Top (ckbMatchCase) + 1, State = _matchWholeWord ? CheckState.Checked : CheckState.UnChecked, Text = "Match _whole word" }; ckbMatchWholeWord.Toggle += (s, e) => _matchWholeWord = e.NewValue == CheckState.Checked; d.Add (ckbMatchWholeWord); return d; } private bool Save () { if (_fileName != null) { // FIXED: BUGBUG: #279 TextView does not know how to deal with \r\n, only \r // As a result files saved on Windows and then read back will show invalid chars. return SaveFile (_appWindow.Title, _fileName); } return SaveAs (); } private bool SaveAs () { List aTypes = new () { new AllowedType ("Text Files", ".txt", ".bin", ".xml"), new AllowedTypeAny () }; var sd = new SaveDialog { Title = "Save file", AllowedTypes = aTypes }; sd.Path = _appWindow.Title; Application.Run (sd); bool canceled = sd.Canceled; string path = sd.Path; string fileName = sd.FileName; sd.Dispose (); if (!canceled) { if (File.Exists (path)) { if (MessageBox.Query ( "Save File", "File already exists. Overwrite any way?", "No", "Ok" ) == 1) { return SaveFile (fileName, path); } _saved = false; return _saved; } return SaveFile (fileName, path); } _saved = false; return _saved; } private bool SaveFile (string title, string file) { try { _appWindow.Title = title; _fileName = file; File.WriteAllText (_fileName, _textView.Text); _originalText = Encoding.Unicode.GetBytes (_textView.Text); _saved = true; _textView.ClearHistoryChanges (); MessageBox.Query ("Save File", "File was successfully saved.", "Ok"); } catch (Exception ex) { MessageBox.ErrorQuery ("Error", ex.Message, "Ok"); return false; } return true; } private void SelectAll () { _textView.SelectAll (); } private void SetFindText () { _textToFind = !string.IsNullOrEmpty (_textView.SelectedText) ? _textView.SelectedText : string.IsNullOrEmpty (_textToFind) ? "" : _textToFind; _textToReplace = string.IsNullOrEmpty (_textToReplace) ? "" : _textToReplace; } }