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.Diagnostics; 23 using System.Windows.Forms; 24 25 using KeePass.Resources; 26 using KeePass.Util; 27 28 namespace KeePass.UI 29 { 30 public sealed class RichTextBoxContextMenu 31 { 32 private RichTextBox m_rtb = null; 33 private Form m_form = null; 34 private CustomContextMenuStripEx m_ctx = null; 35 private ToolStripItem[] m_vMenuItems = 36 new ToolStripItem[(int)RtbCtxCommands.Count]; 37 private string m_strCurLink = string.Empty; 38 39 private enum RtbCtxCommands 40 { 41 Undo = 0, 42 Cut, 43 Copy, 44 Paste, 45 Delete, 46 CopyLink, 47 CopyAll, 48 SelectAll, 49 Count 50 } 51 RichTextBoxContextMenu()52 public RichTextBoxContextMenu() 53 { 54 } 55 ~RichTextBoxContextMenu()56 ~RichTextBoxContextMenu() 57 { 58 try { Detach(); } 59 catch(Exception) { Debug.Assert(false); } 60 } 61 62 [Obsolete] Attach(RichTextBox rtb)63 public void Attach(RichTextBox rtb) 64 { 65 Attach(rtb, null); 66 } 67 Attach(RichTextBox rtb, Form fParent)68 public void Attach(RichTextBox rtb, Form fParent) 69 { 70 Detach(); 71 72 m_rtb = rtb; 73 m_form = fParent; 74 75 m_ctx = CreateContextMenu(); 76 m_ctx.Opening += this.OnMenuOpening; 77 78 m_rtb.ContextMenuStrip = m_ctx; 79 } 80 Detach()81 public void Detach() 82 { 83 if(m_rtb != null) 84 { 85 m_rtb.ContextMenuStrip = null; 86 87 m_ctx.Opening -= this.OnMenuOpening; 88 m_ctx = null; 89 90 for(int i = 0; i < (int)RtbCtxCommands.Count; ++i) 91 m_vMenuItems[i] = null; 92 93 m_rtb = null; 94 m_form = null; 95 } 96 } 97 CreateContextMenu()98 private CustomContextMenuStripEx CreateContextMenu() 99 { 100 CustomContextMenuStripEx ctx = new CustomContextMenuStripEx(); 101 int iPos = -1; 102 103 ToolStripItem tsiUndo = ctx.Items.Add(KPRes.Undo, 104 Properties.Resources.B16x16_Undo, this.OnUndoCommand); 105 tsiUndo.RightToLeftAutoMirrorImage = true; 106 m_vMenuItems[++iPos] = tsiUndo; 107 ctx.Items.Add(new ToolStripSeparator()); 108 109 m_vMenuItems[++iPos] = ctx.Items.Add(KPRes.Cut, 110 Properties.Resources.B16x16_Cut, this.OnCutCommand); 111 m_vMenuItems[++iPos] = ctx.Items.Add(KPRes.Copy, 112 Properties.Resources.B16x16_EditCopy, this.OnCopyCommand); 113 m_vMenuItems[++iPos] = ctx.Items.Add(KPRes.Paste, 114 Properties.Resources.B16x16_EditPaste, this.OnPasteCommand); 115 m_vMenuItems[++iPos] = ctx.Items.Add(KPRes.Delete, 116 Properties.Resources.B16x16_EditDelete, this.OnDeleteCommand); 117 ctx.Items.Add(new ToolStripSeparator()); 118 119 ToolStripItem tsiLink = ctx.Items.Add(KPRes.CopyLink, 120 Properties.Resources.B16x16_EditCopyLink, this.OnCopyLinkCommand); 121 tsiLink.RightToLeftAutoMirrorImage = true; 122 m_vMenuItems[++iPos] = tsiLink; 123 m_vMenuItems[++iPos] = ctx.Items.Add(KPRes.CopyAll, 124 Properties.Resources.B16x16_EditShred, this.OnCopyAllCommand); 125 m_vMenuItems[++iPos] = ctx.Items.Add(KPRes.SelectAll, 126 Properties.Resources.B16x16_Edit, this.OnSelectAllCommand); 127 128 Debug.Assert(iPos == ((int)RtbCtxCommands.Count - 1)); 129 return ctx; 130 } 131 OnMenuOpening(object sender, EventArgs e)132 private void OnMenuOpening(object sender, EventArgs e) 133 { 134 bool bHasText = (m_rtb.TextLength > 0); 135 bool bHasSel = (m_rtb.SelectionLength > 0); 136 137 if(m_rtb.ReadOnly) 138 { 139 m_vMenuItems[(int)RtbCtxCommands.Undo].Enabled = false; 140 m_vMenuItems[(int)RtbCtxCommands.Cut].Enabled = false; 141 m_vMenuItems[(int)RtbCtxCommands.Paste].Enabled = false; 142 m_vMenuItems[(int)RtbCtxCommands.Delete].Enabled = false; 143 } 144 else // Editable 145 { 146 m_vMenuItems[(int)RtbCtxCommands.Undo].Enabled = m_rtb.CanUndo; 147 m_vMenuItems[(int)RtbCtxCommands.Cut].Enabled = bHasSel; 148 m_vMenuItems[(int)RtbCtxCommands.Paste].Enabled = true; // Optimistic 149 m_vMenuItems[(int)RtbCtxCommands.Delete].Enabled = bHasSel; 150 } 151 152 m_vMenuItems[(int)RtbCtxCommands.Copy].Enabled = bHasSel; 153 m_vMenuItems[(int)RtbCtxCommands.CopyAll].Enabled = bHasText; 154 m_vMenuItems[(int)RtbCtxCommands.SelectAll].Enabled = bHasText; 155 156 m_strCurLink = GetLinkBelowMouse(); 157 m_vMenuItems[(int)RtbCtxCommands.CopyLink].Enabled = (m_strCurLink.Length > 0); 158 } 159 GetLinkBelowMouse()160 private string GetLinkBelowMouse() 161 { 162 // Save selection 163 int iSelStart = m_rtb.SelectionStart, iSelLength = m_rtb.SelectionLength; 164 165 string strLink = string.Empty; 166 try 167 { 168 int p = m_rtb.GetCharIndexFromPosition(m_rtb.PointToClient( 169 Cursor.Position)); 170 m_rtb.Select(p, 1); 171 if(UIUtil.RtfIsFirstCharLink(m_rtb)) 172 { 173 int l = p; 174 while((l - 1) >= 0) 175 { 176 m_rtb.Select(l - 1, 1); 177 if(!UIUtil.RtfIsFirstCharLink(m_rtb)) break; 178 --l; 179 } 180 181 int r = p, n = m_rtb.TextLength; 182 while((r + 1) < n) 183 { 184 m_rtb.Select(r + 1, 1); 185 if(!UIUtil.RtfIsFirstCharLink(m_rtb)) break; 186 ++r; 187 } 188 189 strLink = m_rtb.Text.Substring(l, r - l + 1); 190 } 191 } 192 catch(Exception) { Debug.Assert(false); } 193 194 m_rtb.Select(iSelStart, iSelLength); // Restore selection 195 return strLink; 196 } 197 OnUndoCommand(object sender, EventArgs e)198 private void OnUndoCommand(object sender, EventArgs e) 199 { 200 m_rtb.Undo(); 201 } 202 OnCutCommand(object sender, EventArgs e)203 private void OnCutCommand(object sender, EventArgs e) 204 { 205 m_rtb.Cut(); 206 } 207 OnCopyCommand(object sender, EventArgs e)208 private void OnCopyCommand(object sender, EventArgs e) 209 { 210 m_rtb.Copy(); 211 } 212 OnPasteCommand(object sender, EventArgs e)213 private void OnPasteCommand(object sender, EventArgs e) 214 { 215 CustomRichTextBoxEx crtb = (m_rtb as CustomRichTextBoxEx); 216 if(crtb != null) crtb.PasteAcceptable(); 217 else m_rtb.Paste(); 218 } 219 OnDeleteCommand(object sender, EventArgs e)220 private void OnDeleteCommand(object sender, EventArgs e) 221 { 222 // The following resets formattings 223 /* int nStart = m_rtb.SelectionStart, nLength = m_rtb.SelectionLength; 224 if((nStart < 0) || (nLength <= 0)) return; 225 string strText = m_rtb.Text; 226 strText = strText.Remove(nStart, nLength); 227 m_rtb.Text = strText; 228 m_rtb.Select(nStart, 0); */ 229 230 m_rtb.SelectedText = string.Empty; 231 } 232 OnCopyLinkCommand(object sender, EventArgs e)233 private void OnCopyLinkCommand(object sender, EventArgs e) 234 { 235 ClipboardUtil.Copy(m_strCurLink, false, false, null, null, 236 (m_form != null) ? m_form.Handle : IntPtr.Zero); 237 } 238 OnCopyAllCommand(object sender, EventArgs e)239 private void OnCopyAllCommand(object sender, EventArgs e) 240 { 241 int nStart = m_rtb.SelectionStart, nLength = m_rtb.SelectionLength; 242 m_rtb.SelectAll(); 243 m_rtb.Copy(); 244 m_rtb.Select(nStart, nLength); 245 } 246 OnSelectAllCommand(object sender, EventArgs e)247 private void OnSelectAllCommand(object sender, EventArgs e) 248 { 249 m_rtb.SelectAll(); 250 } 251 } 252 } 253