1 /*
2   KeePass Password Safe - The Open-Source Password Manager
3   Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 
20 using System;
21 using System.Collections.Generic;
22 using System.ComponentModel;
23 using System.Diagnostics;
24 using System.Drawing;
25 using System.Drawing.Text;
26 using System.Text;
27 using System.Windows.Forms;
28 
29 using KeePass.App;
30 using KeePass.App.Configuration;
31 using KeePass.Native;
32 using KeePass.Resources;
33 using KeePass.UI;
34 using KeePass.Util;
35 
36 using KeePassLib;
37 using KeePassLib.Utility;
38 
39 using NativeLib = KeePassLib.Native.NativeLib;
40 
41 namespace KeePass.Forms
42 {
43 	public partial class DataEditorForm : Form
44 	{
45 		private string m_strDataDesc = string.Empty;
46 		private byte[] m_pbData = null;
47 		private byte[] m_pbEditedData = null;
48 
49 		private bool m_bModified = false;
50 		private bool m_bURtfWithHighChar = false;
51 
52 		private uint m_uBlockEvents = 0;
53 		private Stack<KeyValuePair<int, int>> m_lSelections =
54 			new Stack<KeyValuePair<int, int>>();
55 		private BinaryDataClass m_bdc = BinaryDataClass.Unknown;
56 		private bool m_bNewLinesWin = true;
57 
58 		private string m_strInitialFormRect = string.Empty;
59 		private RichTextBoxContextMenu m_ctxText = new RichTextBoxContextMenu();
60 
61 		/// <summary>
62 		/// Get the edited, new data. This property is non-<c>null</c> only
63 		/// if the user has really edited the data (i.e. if the user makes no
64 		/// changes, <c>null</c> is returned).
65 		/// </summary>
66 		public byte[] EditedBinaryData
67 		{
68 			get { return m_pbEditedData; }
69 		}
70 
71 		public MenuStrip MainMenuEx { get { return m_menuMain; } }
72 
SupportsDataType(BinaryDataClass bdc)73 		public static bool SupportsDataType(BinaryDataClass bdc)
74 		{
75 			return ((bdc == BinaryDataClass.Text) || (bdc == BinaryDataClass.RichText));
76 		}
77 
InitEx(string strDataDesc, byte[] pbData)78 		public void InitEx(string strDataDesc, byte[] pbData)
79 		{
80 			if(strDataDesc != null) m_strDataDesc = strDataDesc;
81 
82 			m_pbData = pbData;
83 		}
84 
DataEditorForm()85 		public DataEditorForm()
86 		{
87 			InitializeComponent();
88 
89 			GlobalWindowManager.InitializeForm(this);
90 			Program.Translation.ApplyTo("KeePass.Forms.DataEditorForm.m_menuMain", m_menuMain.Items);
91 		}
92 
OnFormLoad(object sender, EventArgs e)93 		private void OnFormLoad(object sender, EventArgs e)
94 		{
95 			Debug.Assert(m_pbData != null);
96 			if(m_pbData == null) throw new InvalidOperationException();
97 
98 			GlobalWindowManager.AddWindow(this);
99 
100 			this.Icon = AppIcons.Default;
101 			this.DoubleBuffered = true;
102 
103 			m_strInitialFormRect = UIUtil.SetWindowScreenRectEx(this,
104 				Program.Config.UI.DataEditorRect);
105 
106 			m_bdc = BinaryDataClassifier.Classify(m_strDataDesc, m_pbData);
107 			uint uStartOffset;
108 			StrEncodingInfo seiGuess = BinaryDataClassifier.GetStringEncoding(
109 				m_pbData, out uStartOffset);
110 			string strData;
111 			try
112 			{
113 				strData = (seiGuess.Encoding.GetString(m_pbData, (int)uStartOffset,
114 					m_pbData.Length - (int)uStartOffset) ?? string.Empty);
115 				strData = StrUtil.ReplaceNulls(strData);
116 			}
117 			catch(Exception) { Debug.Assert(false); strData = string.Empty; }
118 
119 			++m_uBlockEvents;
120 
121 			UIUtil.AssignShortcut(m_menuFileSave, Keys.Control | Keys.S);
122 			UIUtil.AssignShortcut(m_menuFileExit, Keys.Escape, null, true);
123 			UIUtil.AssignShortcut(m_menuEditUndo, Keys.Control | Keys.Z, null, true);
124 			UIUtil.AssignShortcut(m_menuEditRedo, Keys.Control | Keys.Y, null, true);
125 			UIUtil.AssignShortcut(m_menuEditCut, Keys.Control | Keys.X, null, true);
126 			UIUtil.AssignShortcut(m_menuEditCopy, Keys.Control | Keys.C, null, true);
127 			UIUtil.AssignShortcut(m_menuEditPaste, Keys.Control | Keys.V, null, true);
128 			UIUtil.AssignShortcut(m_menuEditDelete, Keys.Delete, null, true);
129 			UIUtil.AssignShortcut(m_menuEditSelectAll, Keys.Control | Keys.A, null, true);
130 			UIUtil.AssignShortcut(m_menuEditFind, Keys.Control | Keys.F);
131 
132 			UIUtil.ConfigureTbButton(m_tbFileSave, KPRes.Save, null, m_menuFileSave);
133 			UIUtil.ConfigureTbButton(m_tbEditCut, KPRes.Cut, null, m_menuEditCut);
134 			UIUtil.ConfigureTbButton(m_tbEditCopy, KPRes.Copy, null, m_menuEditCopy);
135 			UIUtil.ConfigureTbButton(m_tbEditPaste, KPRes.Paste, null, m_menuEditPaste);
136 			UIUtil.ConfigureTbButton(m_tbEditUndo, KPRes.Undo, null, m_menuEditUndo);
137 			UIUtil.ConfigureTbButton(m_tbEditRedo, KPRes.Redo, null, m_menuEditRedo);
138 			UIUtil.ConfigureTbButton(m_tbFind, null, KPRes.Find, m_menuEditFind);
139 
140 			// Formatting keyboard shortcuts are implemented by CustomRichTextBoxEx
141 			UIUtil.ConfigureTbButton(m_tbFormatBold, KPRes.Bold, KPRes.Bold +
142 				" (" + UIUtil.GetKeysName(Keys.Control | Keys.B) + ")", null);
143 			UIUtil.ConfigureTbButton(m_tbFormatItalic, KPRes.Italic, KPRes.Italic +
144 				" (" + UIUtil.GetKeysName(Keys.Control | Keys.I) + ")", null);
145 			UIUtil.ConfigureTbButton(m_tbFormatUnderline, KPRes.Underline, KPRes.Underline +
146 				" (" + UIUtil.GetKeysName(Keys.Control | Keys.U) + ")", null);
147 			UIUtil.ConfigureTbButton(m_tbFormatStrikeout, KPRes.Strikeout, null);
148 			UIUtil.ConfigureTbButton(m_tbColorForeground, KPRes.TextColor, null);
149 			UIUtil.ConfigureTbButton(m_tbColorBackground, KPRes.BackgroundColor, null);
150 			UIUtil.ConfigureTbButton(m_tbAlignLeft, KPRes.AlignLeft, KPRes.AlignLeft +
151 				" (" + UIUtil.GetKeysName(Keys.Control | Keys.L) + ")", null);
152 			UIUtil.ConfigureTbButton(m_tbAlignCenter, KPRes.AlignCenter, KPRes.AlignCenter +
153 				" (" + UIUtil.GetKeysName(Keys.Control | Keys.E) + ")", null);
154 			UIUtil.ConfigureTbButton(m_tbAlignRight, KPRes.AlignRight, KPRes.AlignRight +
155 				" (" + UIUtil.GetKeysName(Keys.Control | Keys.R) + ")", null);
156 
157 			string strSearchTr = ((WinUtil.IsAtLeastWindowsVista ?
158 				string.Empty : " ") + KPRes.Search);
159 			UIUtil.SetCueBanner(m_tbFind, strSearchTr);
160 
161 			UIUtil.SetToolTip(m_tbFontCombo, KPRes.Font, true);
162 			UIUtil.SetToolTip(m_tbFontSizeCombo, KPRes.Size, true);
163 
164 			UIUtil.EnableAutoCompletion(m_tbFontCombo, true);
165 			UIUtil.EnableAutoCompletion(m_tbFontSizeCombo, true);
166 
167 			m_rtbText.WordWrap = Program.Config.UI.DataEditorWordWrap;
168 			m_ctxText.Attach(m_rtbText, this);
169 			m_tssStatusMain.Text = KPRes.Ready;
170 
171 			InitFormattingToolBar();
172 
173 			bool bSimpleText = true, bDefaultFont = true;
174 			if(m_bdc == BinaryDataClass.RichText)
175 			{
176 				try
177 				{
178 					if(strData.Length > 0)
179 					{
180 						m_rtbText.Rtf = StrUtil.RtfFix(strData);
181 						bDefaultFont = false;
182 					}
183 					else m_rtbText.Text = string.Empty;
184 
185 					bSimpleText = false;
186 				}
187 				catch(Exception) { } // Show as simple text
188 			}
189 
190 			if(bSimpleText)
191 			{
192 				m_rtbText.Text = strData;
193 				m_rtbText.SimpleTextOnly = true;
194 
195 				// CR is upgraded to CR+LF
196 				m_bNewLinesWin = (StrUtil.GetNewLineSeq(strData) != "\n");
197 			}
198 			else m_menuViewFont.Text = KPRes.FontDefault + "...";
199 
200 			if(bDefaultFont && Program.Config.UI.DataEditorFont.OverrideUIDefault)
201 			{
202 				m_rtbText.SelectAll();
203 				m_rtbText.SelectionFont = Program.Config.UI.DataEditorFont.ToFont();
204 			}
205 
206 			m_rtbText.Select(0, 0);
207 			--m_uBlockEvents;
208 			UpdateUIState(false, true);
209 		}
210 
InitFormattingToolBar()211 		private void InitFormattingToolBar()
212 		{
213 			if(m_bdc != BinaryDataClass.RichText)
214 			{
215 				m_toolFormat.Visible = false;
216 				return;
217 			}
218 
219 			using(InstalledFontCollection c = new InstalledFontCollection())
220 			{
221 				foreach(FontFamily ff in c.Families)
222 					m_tbFontCombo.Items.Add(ff.Name);
223 			}
224 
225 			int[] vSizes = new int[] { 8, 9, 10, 11, 12, 14, 16, 18, 20,
226 				22, 24, 26, 28, 36, 48, 72 };
227 			foreach(int nSize in vSizes)
228 				m_tbFontSizeCombo.Items.Add(nSize.ToString());
229 		}
230 
UpdateUIState(bool bSetModified, bool bFocusText)231 		private void UpdateUIState(bool bSetModified, bool bFocusText)
232 		{
233 			++m_uBlockEvents;
234 			if(bSetModified) m_bModified = true;
235 
236 			this.Text = (((m_strDataDesc.Length > 0) ? (m_strDataDesc +
237 				(m_bModified ? "*" : string.Empty) + " - ") : string.Empty) +
238 				KPRes.DataEditorKP);
239 
240 			// m_menuViewFont.Enabled = (m_bdc == BinaryDataClass.Text);
241 			UIUtil.SetChecked(m_menuViewWordWrap, m_rtbText.WordWrap);
242 
243 			m_tbFileSave.Image = (m_bModified ? Properties.Resources.B16x16_FileSave :
244 				Properties.Resources.B16x16_FileSave_Disabled);
245 
246 			UIUtil.SetEnabledFast(m_rtbText.CanUndo, m_menuEditUndo, m_tbEditUndo);
247 			UIUtil.SetEnabledFast(m_rtbText.CanRedo, m_menuEditRedo, m_tbEditRedo);
248 
249 			bool bSel = (m_rtbText.SelectionLength != 0);
250 			UIUtil.SetEnabledFast(bSel, m_menuEditCut, m_tbEditCut,
251 				m_menuEditCopy, m_tbEditCopy, m_menuEditDelete);
252 
253 			Font fSel = m_rtbText.SelectionFont;
254 			if(fSel != null)
255 			{
256 				m_tbFormatBold.Checked = fSel.Bold;
257 				m_tbFormatItalic.Checked = fSel.Italic;
258 				m_tbFormatUnderline.Checked = fSel.Underline;
259 				m_tbFormatStrikeout.Checked = fSel.Strikeout;
260 
261 				string strFontName = fSel.Name;
262 				if(m_tbFontCombo.Items.IndexOf(strFontName) >= 0)
263 					m_tbFontCombo.SelectedItem = strFontName;
264 				else m_tbFontCombo.Text = strFontName;
265 
266 				string strFontSize = fSel.SizeInPoints.ToString();
267 				if(m_tbFontSizeCombo.Items.IndexOf(strFontSize) >= 0)
268 					m_tbFontSizeCombo.SelectedItem = strFontSize;
269 				else m_tbFontSizeCombo.Text = strFontSize;
270 			}
271 
272 			HorizontalAlignment ha = m_rtbText.SelectionAlignment;
273 			m_tbAlignLeft.Checked = (ha == HorizontalAlignment.Left);
274 			m_tbAlignCenter.Checked = (ha == HorizontalAlignment.Center);
275 			m_tbAlignRight.Checked = (ha == HorizontalAlignment.Right);
276 
277 			--m_uBlockEvents;
278 			if(bFocusText) UIUtil.SetFocus(m_rtbText, this);
279 		}
280 
UISelectAllText(bool bSelect)281 		private void UISelectAllText(bool bSelect)
282 		{
283 			if(bSelect)
284 			{
285 				m_lSelections.Push(new KeyValuePair<int, int>(m_rtbText.SelectionStart,
286 					m_rtbText.SelectionLength));
287 				m_rtbText.SelectAll();
288 			}
289 			else
290 			{
291 				KeyValuePair<int, int> kvp = m_lSelections.Pop();
292 				m_rtbText.Select(kvp.Key, kvp.Value);
293 			}
294 		}
295 
OnFileSave(object sender, EventArgs e)296 		private void OnFileSave(object sender, EventArgs e)
297 		{
298 			if(m_bdc == BinaryDataClass.RichText)
299 			{
300 				string strRtf = m_rtbText.Rtf;
301 
302 				if(StrUtil.RtfIsURtf(strRtf))
303 					m_bURtfWithHighChar = StrUtil.ContainsHighChar(m_rtbText.Text);
304 				else m_bURtfWithHighChar = false;
305 
306 				m_pbEditedData = StrUtil.Utf8.GetBytes(StrUtil.RtfFix(strRtf));
307 			}
308 			else
309 			{
310 				string strData = m_rtbText.Text;
311 				strData = StrUtil.NormalizeNewLines(strData, m_bNewLinesWin);
312 				m_pbEditedData = StrUtil.Utf8.GetBytes(strData);
313 			}
314 
315 			m_bModified = false;
316 			UpdateUIState(false, false);
317 		}
318 
OnFormClosing(object sender, FormClosingEventArgs e)319 		private void OnFormClosing(object sender, FormClosingEventArgs e)
320 		{
321 			if(m_bModified)
322 			{
323 				DialogResult dr = MessageService.Ask(KPRes.SaveBeforeCloseQuestion,
324 					PwDefs.ShortProductName, MessageBoxButtons.YesNoCancel);
325 
326 				if(dr == DialogResult.Yes)
327 					OnFileSave(sender, EventArgs.Empty);
328 				else if(dr == DialogResult.No) { }
329 				else
330 				{
331 					e.Cancel = true;
332 					return;
333 				}
334 			}
335 
336 			if(m_bURtfWithHighChar && (m_pbEditedData != null) &&
337 				!MemUtil.ArraysEqual(m_pbEditedData, m_pbData))
338 			{
339 				string strUrl = AppHelp.GetOnlineUrl(AppDefs.HelpTopics.KbFaq,
340 					AppDefs.HelpTopics.KbFaqURtf);
341 				string strLink = VistaTaskDialog.CreateLink(strUrl, strUrl);
342 				string strMsg = KPRes.URtfProblem + MessageService.NewParagraph +
343 					KPRes.URtfCheck + MessageService.NewParagraph +
344 					KPRes.URtfSuggestion + MessageService.NewParagraph +
345 					KPRes.MoreInfo + ":" + MessageService.NewLine;
346 
347 				VistaTaskDialog dlg = new VistaTaskDialog();
348 				dlg.AddButton((int)DialogResult.Cancel, KPRes.Ok, null);
349 				dlg.CommandLinks = false;
350 				dlg.Content = strMsg + strLink;
351 				dlg.DefaultButtonID = (int)DialogResult.Cancel;
352 				dlg.EnableHyperlinks = true;
353 				dlg.SetIcon(VtdIcon.Warning);
354 				dlg.WindowTitle = PwDefs.ShortProductName;
355 
356 				if(!dlg.ShowDialog())
357 					MessageService.ShowWarning(strMsg + strUrl);
358 			}
359 
360 			Debug.Assert(m_uBlockEvents == 0);
361 
362 			string strRect = UIUtil.GetWindowScreenRect(this);
363 			if(strRect != m_strInitialFormRect) // Don't overwrite ""
364 				Program.Config.UI.DataEditorRect = strRect;
365 		}
366 
OnFormClosed(object sender, FormClosedEventArgs e)367 		private void OnFormClosed(object sender, FormClosedEventArgs e)
368 		{
369 			m_ctxText.Detach();
370 			GlobalWindowManager.RemoveWindow(this);
371 		}
372 
ToggleSelectionFormat(FontStyle fs)373 		private void ToggleSelectionFormat(FontStyle fs)
374 		{
375 			if((m_uBlockEvents > 0) || (m_bdc != BinaryDataClass.RichText)) return;
376 
377 			UIUtil.RtfToggleSelectionFormat(m_rtbText, fs);
378 			UpdateUIState(true, true);
379 		}
380 
OnFormatBoldClicked(object sender, EventArgs e)381 		private void OnFormatBoldClicked(object sender, EventArgs e)
382 		{
383 			ToggleSelectionFormat(FontStyle.Bold);
384 		}
385 
OnFormatItalicClicked(object sender, EventArgs e)386 		private void OnFormatItalicClicked(object sender, EventArgs e)
387 		{
388 			ToggleSelectionFormat(FontStyle.Italic);
389 		}
390 
OnFormatUnderlineClicked(object sender, EventArgs e)391 		private void OnFormatUnderlineClicked(object sender, EventArgs e)
392 		{
393 			ToggleSelectionFormat(FontStyle.Underline);
394 		}
395 
OnFormatStrikeoutClicked(object sender, EventArgs e)396 		private void OnFormatStrikeoutClicked(object sender, EventArgs e)
397 		{
398 			ToggleSelectionFormat(FontStyle.Strikeout);
399 		}
400 
OnTextSelectionChanged(object sender, EventArgs e)401 		private void OnTextSelectionChanged(object sender, EventArgs e)
402 		{
403 			if(m_uBlockEvents > 0) return;
404 
405 			UpdateUIState(false, false);
406 		}
407 
ShowColorDialog(Color clrCurrent, out Color clrSelected)408 		private static bool ShowColorDialog(Color clrCurrent, out Color clrSelected)
409 		{
410 			Color? clrNew = UIUtil.ShowColorDialog(clrCurrent);
411 			clrSelected = clrNew.GetValueOrDefault(clrCurrent);
412 			return clrNew.HasValue;
413 		}
414 
OnColorForegroundClicked(object sender, EventArgs e)415 		private void OnColorForegroundClicked(object sender, EventArgs e)
416 		{
417 			if((m_uBlockEvents > 0) || (m_bdc != BinaryDataClass.RichText)) return;
418 
419 			Color clr;
420 			if(ShowColorDialog(m_rtbText.SelectionColor, out clr))
421 			{
422 				m_rtbText.SelectionColor = clr;
423 				UpdateUIState(true, true);
424 			}
425 		}
426 
OnColorBackgroundClicked(object sender, EventArgs e)427 		private void OnColorBackgroundClicked(object sender, EventArgs e)
428 		{
429 			if((m_uBlockEvents > 0) || (m_bdc != BinaryDataClass.RichText)) return;
430 
431 			Color clr;
432 			if(ShowColorDialog(m_rtbText.SelectionBackColor, out clr))
433 			{
434 				m_rtbText.SelectionBackColor = clr;
435 				UpdateUIState(true, true);
436 			}
437 		}
438 
OnFileExit(object sender, EventArgs e)439 		private void OnFileExit(object sender, EventArgs e)
440 		{
441 			this.DialogResult = DialogResult.OK;
442 		}
443 
OnTextTextChanged(object sender, EventArgs e)444 		private void OnTextTextChanged(object sender, EventArgs e)
445 		{
446 			if(m_uBlockEvents > 0) return;
447 
448 			UpdateUIState(true, false);
449 		}
450 
OnAlignLeftClicked(object sender, EventArgs e)451 		private void OnAlignLeftClicked(object sender, EventArgs e)
452 		{
453 			if((m_uBlockEvents > 0) || (m_bdc != BinaryDataClass.RichText)) return;
454 
455 			m_rtbText.SelectionAlignment = HorizontalAlignment.Left;
456 
457 			UpdateUIState(true, true);
458 		}
459 
OnAlignCenterClicked(object sender, EventArgs e)460 		private void OnAlignCenterClicked(object sender, EventArgs e)
461 		{
462 			if((m_uBlockEvents > 0) || (m_bdc != BinaryDataClass.RichText)) return;
463 
464 			m_rtbText.SelectionAlignment = HorizontalAlignment.Center;
465 
466 			UpdateUIState(true, true);
467 		}
468 
OnAlignRightClicked(object sender, EventArgs e)469 		private void OnAlignRightClicked(object sender, EventArgs e)
470 		{
471 			if((m_uBlockEvents > 0) || (m_bdc != BinaryDataClass.RichText)) return;
472 
473 			m_rtbText.SelectionAlignment = HorizontalAlignment.Right;
474 
475 			UpdateUIState(true, true);
476 		}
477 
OnFontComboSelectedIndexChanged(object sender, EventArgs e)478 		private void OnFontComboSelectedIndexChanged(object sender, EventArgs e)
479 		{
480 			if((m_uBlockEvents > 0) || (m_bdc != BinaryDataClass.RichText)) return;
481 
482 			try
483 			{
484 				string strName = m_tbFontCombo.Text;
485 
486 				Font f = m_rtbText.SelectionFont;
487 				if(f != null)
488 					m_rtbText.SelectionFont = new Font(strName, f.Size,
489 						f.Style, f.Unit, f.GdiCharSet, f.GdiVerticalFont);
490 				else if(FontUtil.DefaultFont != null)
491 					m_rtbText.SelectionFont = FontUtil.CreateFont(strName,
492 						FontUtil.DefaultFont.SizeInPoints, FontStyle.Regular);
493 				else
494 					m_rtbText.SelectionFont = FontUtil.CreateFont(strName,
495 						12.0f, FontStyle.Regular);
496 			}
497 			catch(Exception ex) { MessageService.ShowWarning(ex); }
498 
499 			UpdateUIState(true, true);
500 		}
501 
OnFontSizeComboSelectedIndexChanged(object sender, EventArgs e)502 		private void OnFontSizeComboSelectedIndexChanged(object sender, EventArgs e)
503 		{
504 			if((m_uBlockEvents > 0) || (m_bdc != BinaryDataClass.RichText)) return;
505 
506 			try
507 			{
508 				Font f = m_rtbText.SelectionFont;
509 				float fSize;
510 				if(!float.TryParse(m_tbFontSizeCombo.Text, out fSize))
511 				{
512 					if(f != null) fSize = f.SizeInPoints;
513 					else if(FontUtil.DefaultFont != null)
514 						fSize = FontUtil.DefaultFont.SizeInPoints;
515 					else fSize = 12.0f;
516 				}
517 
518 				if(f != null)
519 					m_rtbText.SelectionFont = new Font(f.Name, fSize, f.Style,
520 						GraphicsUnit.Point, f.GdiCharSet, f.GdiVerticalFont);
521 				else if(!NativeLib.IsUnix())
522 					UIUtil.RtfSetFontSize(m_rtbText, fSize);
523 				else // Unix
524 					m_rtbText.SelectionFont = FontUtil.CreateFont(
525 						FontFamily.GenericSansSerif, fSize, FontStyle.Regular);
526 			}
527 			catch(Exception ex) { MessageService.ShowWarning(ex); }
528 
529 			UpdateUIState(true, true);
530 		}
531 
OnFontComboKeyDown(object sender, KeyEventArgs e)532 		private void OnFontComboKeyDown(object sender, KeyEventArgs e)
533 		{
534 			if(e.KeyCode == Keys.Return) // Return == Enter
535 			{
536 				UIUtil.SetHandled(e, true);
537 				OnFontComboSelectedIndexChanged(sender, e);
538 			}
539 		}
540 
OnFontSizeComboKeyDown(object sender, KeyEventArgs e)541 		private void OnFontSizeComboKeyDown(object sender, KeyEventArgs e)
542 		{
543 			if(e.KeyCode == Keys.Return) // Return == Enter
544 			{
545 				UIUtil.SetHandled(e, true);
546 				OnFontSizeComboSelectedIndexChanged(sender, e);
547 			}
548 		}
549 
OnEditCut(object sender, EventArgs e)550 		private void OnEditCut(object sender, EventArgs e)
551 		{
552 			m_rtbText.Cut();
553 			UpdateUIState(true, true);
554 		}
555 
OnEditCopy(object sender, EventArgs e)556 		private void OnEditCopy(object sender, EventArgs e)
557 		{
558 			m_rtbText.Copy();
559 			UpdateUIState(false, true);
560 		}
561 
OnEditPaste(object sender, EventArgs e)562 		private void OnEditPaste(object sender, EventArgs e)
563 		{
564 			m_rtbText.PasteAcceptable();
565 			UpdateUIState(true, true);
566 		}
567 
OnEditUndo(object sender, EventArgs e)568 		private void OnEditUndo(object sender, EventArgs e)
569 		{
570 			m_rtbText.Undo();
571 			UpdateUIState(true, true);
572 		}
573 
OnEditRedo(object sender, EventArgs e)574 		private void OnEditRedo(object sender, EventArgs e)
575 		{
576 			m_rtbText.Redo();
577 			UpdateUIState(true, true);
578 		}
579 
OnViewFont(object sender, EventArgs e)580 		private void OnViewFont(object sender, EventArgs e)
581 		{
582 			FontDialog dlg = UIUtil.CreateFontDialog(true);
583 			dlg.Font = Program.Config.UI.DataEditorFont.ToFont();
584 			dlg.ShowColor = false;
585 
586 			if(dlg.ShowDialog() == DialogResult.OK)
587 			{
588 				Program.Config.UI.DataEditorFont = new AceFont(dlg.Font);
589 				Program.Config.UI.DataEditorFont.OverrideUIDefault = true;
590 
591 				if(m_bdc == BinaryDataClass.Text)
592 				{
593 					bool bModified = m_bModified; // Save modified state
594 
595 					UISelectAllText(true);
596 					m_rtbText.SelectionFont = dlg.Font;
597 					UISelectAllText(false);
598 
599 					m_bModified = bModified;
600 					UpdateUIState(false, false);
601 				}
602 			}
603 			dlg.Dispose();
604 		}
605 
OnViewWordWrap(object sender, EventArgs e)606 		private void OnViewWordWrap(object sender, EventArgs e)
607 		{
608 			m_rtbText.WordWrap = !m_rtbText.WordWrap;
609 			Program.Config.UI.DataEditorWordWrap = m_rtbText.WordWrap;
610 			UpdateUIState(false, false);
611 		}
612 
ProcessCmdKey(ref Message msg, Keys keyData)613 		protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
614 		{
615 			bool bDown;
616 			if(!NativeMethods.GetKeyMessageState(ref msg, out bDown))
617 				return base.ProcessCmdKey(ref msg, keyData);
618 
619 			if(keyData == Keys.Escape) // No modifiers
620 			{
621 				if(bDown) Close();
622 				return true;
623 			}
624 
625 			return base.ProcessCmdKey(ref msg, keyData);
626 		}
627 
ConvertAttachment(string strDesc, byte[] pbData)628 		internal static byte[] ConvertAttachment(string strDesc, byte[] pbData)
629 		{
630 			BinaryDataClass bdc = BinaryDataClassifier.Classify(strDesc, pbData);
631 			if(bdc == BinaryDataClass.Text)
632 			{
633 				string strContext = (KPRes.File + (string.IsNullOrEmpty(strDesc) ?
634 					string.Empty : (": " + strDesc)));
635 
636 				TextEncodingForm dlg = new TextEncodingForm();
637 				dlg.InitEx(strContext, pbData);
638 				if(UIUtil.ShowDialogNotValue(dlg, DialogResult.OK)) return null;
639 
640 				Encoding enc = dlg.SelectedEncoding;
641 				int iStart = (int)dlg.DataStartOffset;
642 				UIUtil.DestroyForm(dlg);
643 				if(enc != null)
644 				{
645 					try
646 					{
647 						string strText = (enc.GetString(pbData, iStart,
648 							pbData.Length - iStart) ?? string.Empty);
649 						strText = StrUtil.ReplaceNulls(strText);
650 						return StrUtil.Utf8.GetBytes(strText);
651 					}
652 					catch(Exception) { Debug.Assert(false); }
653 				}
654 			}
655 
656 			return pbData;
657 		}
658 
OnTextFindKeyDown(object sender, KeyEventArgs e)659 		private void OnTextFindKeyDown(object sender, KeyEventArgs e)
660 		{
661 			if(e.KeyCode == Keys.Return) // Return == Enter
662 			{
663 				UIUtil.SetHandled(e, true);
664 				PerformQuickFind();
665 			}
666 		}
667 
OnTextFindKeyUp(object sender, KeyEventArgs e)668 		private void OnTextFindKeyUp(object sender, KeyEventArgs e)
669 		{
670 			if(e.KeyCode == Keys.Return) // Return == Enter
671 				UIUtil.SetHandled(e, true);
672 		}
673 
PerformQuickFind()674 		private void PerformQuickFind()
675 		{
676 			string strNeedle = m_tbFind.Text;
677 			if(string.IsNullOrEmpty(strNeedle)) return;
678 
679 			int iStart = m_rtbText.SelectionStart + m_rtbText.SelectionLength;
680 			if(iStart < 0) { Debug.Assert(false); iStart = 0; }
681 			if(iStart >= m_rtbText.TextLength) iStart = 0;
682 
683 			int p = m_rtbText.Find(strNeedle, iStart, -1, RichTextBoxFinds.None);
684 			if(p < 0) m_rtbText.Find(strNeedle, 0, -1, RichTextBoxFinds.None);
685 		}
686 
OnEditSelectAll(object sender, EventArgs e)687 		private void OnEditSelectAll(object sender, EventArgs e)
688 		{
689 			m_rtbText.SelectAll();
690 		}
691 
OnEditFind(object sender, EventArgs e)692 		private void OnEditFind(object sender, EventArgs e)
693 		{
694 			m_tbFind.SelectAll();
695 			UIUtil.SetFocus(m_tbFind.Control, this, true);
696 		}
697 
OnEditDelete(object sender, EventArgs e)698 		private void OnEditDelete(object sender, EventArgs e)
699 		{
700 			m_rtbText.SelectedText = string.Empty;
701 		}
702 	}
703 }
704