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.Drawing;
24 using System.Text;
25 using System.Windows.Forms;
26 
27 using KeePassLib.Delegates;
28 using KeePassLib.Utility;
29 
30 namespace KeePass.UI
31 {
32 	internal sealed class MenuItemLinks
33 	{
34 		private readonly Dictionary<ToolStripItem, ToolStripItem> m_dCopies =
35 			new Dictionary<ToolStripItem, ToolStripItem>();
36 
CreateCopy(ToolStripItemCollection tsicTarget, ToolStripItem tsiPosRef, bool bAfter, ToolStripMenuItem tsmiBase)37 		public void CreateCopy(ToolStripItemCollection tsicTarget,
38 			ToolStripItem tsiPosRef, bool bAfter, ToolStripMenuItem tsmiBase)
39 		{
40 			if(tsicTarget == null) { Debug.Assert(false); return; }
41 			if(tsmiBase == null) { Debug.Assert(false); return; }
42 
43 			ToolStripMenuItem tsmi = new ToolStripMenuItem();
44 
45 			string strName = tsmiBase.Name, strNameNew = null;
46 			if(!string.IsNullOrEmpty(strName))
47 			{
48 				if(strName.StartsWith("m_menu", StrUtil.CaseIgnoreCmp))
49 					strNameNew = "m_ctx" + strName.Substring(6);
50 			}
51 			if(!string.IsNullOrEmpty(strNameNew))
52 			{
53 				ToolStripItem[] v = tsicTarget.Find(strNameNew, true);
54 				if((v == null) || (v.Length == 0))
55 					tsmi.Name = strNameNew;
56 				else { Debug.Assert(false); }
57 			}
58 			else { Debug.Assert(false); }
59 
60 			CreateLink(tsmi, tsmiBase, (tsmiBase.DropDownItems.Count == 0));
61 
62 			int i, n = tsicTarget.Count;
63 			if(tsiPosRef == null) i = (bAfter ? n : 0);
64 			else
65 			{
66 				i = tsicTarget.IndexOf(tsiPosRef);
67 				if(i < 0) { Debug.Assert(false); i = n; }
68 				else if(bAfter) ++i;
69 			}
70 
71 			tsicTarget.Insert(i, tsmi);
72 
73 			foreach(ToolStripItem tsiSub in tsmiBase.DropDownItems)
74 			{
75 				ToolStripMenuItem tsmiSub = (tsiSub as ToolStripMenuItem);
76 				if(tsmiSub != null)
77 					CreateCopy(tsmi.DropDownItems, null, true, tsmiSub);
78 				else if(tsiSub is ToolStripSeparator)
79 					tsmi.DropDownItems.Add(new ToolStripSeparator());
80 				else { Debug.Assert(false); }
81 			}
82 		}
83 
CreateLink(ToolStripMenuItem tsmi, ToolStripMenuItem tsmiBase, bool bHandleClick)84 		public void CreateLink(ToolStripMenuItem tsmi, ToolStripMenuItem tsmiBase,
85 			bool bHandleClick)
86 		{
87 			if(tsmi == null) { Debug.Assert(false); return; }
88 			if(tsmiBase == null) { Debug.Assert(false); return; }
89 
90 			tsmi.Text = tsmiBase.Text;
91 			tsmiBase.TextChanged += delegate(object sender, EventArgs e)
92 			{
93 				Debug.Assert(sender == tsmiBase);
94 				Debug.Assert(tsmi.Text != tsmiBase.Text);
95 				try { tsmi.Text = tsmiBase.Text; }
96 				catch(Exception) { Debug.Assert(false); }
97 			};
98 
99 			tsmi.Image = tsmiBase.Image;
100 			Debug.Assert(object.ReferenceEquals(tsmi.Image, tsmiBase.Image));
101 			Debug.Assert(tsmiBase.ImageTransparentColor == Color.Empty);
102 
103 			tsmi.Size = tsmiBase.Size;
104 
105 			// Getting 'Visible' also checks parent
106 			tsmi.Available = tsmiBase.Available;
107 			tsmiBase.AvailableChanged += delegate(object sender, EventArgs e)
108 			{
109 				Debug.Assert(sender == tsmiBase);
110 				Debug.Assert(tsmi.Available != tsmiBase.Available);
111 				try { tsmi.Available = tsmiBase.Available; }
112 				catch(Exception) { Debug.Assert(false); }
113 			};
114 
115 			VoidDelegate fCopyEnabled = delegate()
116 			{
117 				// Check (direct) owner state; see ToolStripItem.Enabled
118 				ToolStrip tsOwner = tsmiBase.Owner;
119 				if((tsOwner != null) && !tsOwner.Enabled)
120 				{
121 					Debug.Assert(false); // tsmiBase.Enabled unusable
122 					return;
123 				}
124 				tsmi.Enabled = tsmiBase.Enabled;
125 			};
126 
127 			fCopyEnabled();
128 			tsmiBase.EnabledChanged += delegate(object sender, EventArgs e)
129 			{
130 				Debug.Assert(sender == tsmiBase);
131 				Debug.Assert(tsmi.Enabled != tsmiBase.Enabled);
132 				try { fCopyEnabled(); }
133 				catch(Exception) { Debug.Assert(false); }
134 			};
135 
136 			string strSh = tsmiBase.ShortcutKeyDisplayString;
137 			if(!string.IsNullOrEmpty(strSh)) tsmi.ShortcutKeyDisplayString = strSh;
138 
139 			if(bHandleClick)
140 			{
141 				Debug.Assert(tsmiBase.DropDownItems.Count == 0);
142 				tsmi.Click += delegate(object sender, EventArgs e)
143 				{
144 					Debug.Assert(sender == tsmi);
145 					try { tsmiBase.PerformClick(); }
146 					catch(Exception) { Debug.Assert(false); }
147 				};
148 			}
149 
150 			Debug.Assert(!m_dCopies.ContainsKey(tsmiBase)); // One copy only
151 			m_dCopies[tsmiBase] = tsmi;
152 		}
153 
SetCopyAvailable(ToolStripMenuItem tsmiBase, bool bAvailable)154 		public void SetCopyAvailable(ToolStripMenuItem tsmiBase, bool bAvailable)
155 		{
156 			if(tsmiBase == null) { Debug.Assert(false); return; }
157 
158 			ToolStripItem tsi;
159 			if(!m_dCopies.TryGetValue(tsmiBase, out tsi)) { Debug.Assert(false); return; }
160 			tsi.Available = bAvailable;
161 		}
162 
SetImage(ToolStripMenuItem tsmiBase, Image img)163 		public void SetImage(ToolStripMenuItem tsmiBase, Image img)
164 		{
165 			if(tsmiBase == null) { Debug.Assert(false); return; }
166 
167 			tsmiBase.Image = img;
168 
169 			ToolStripItem tsi;
170 			if(!m_dCopies.TryGetValue(tsmiBase, out tsi)) { Debug.Assert(false); return; }
171 			tsi.Image = img;
172 		}
173 	}
174 }
175