OLD | NEW |
| (Empty) |
1 /// Copyright (c) Microsoft Corporation. All rights reserved. | |
2 | |
3 using System; | |
4 using System.Collections; | |
5 using System.ComponentModel; | |
6 using System.Drawing; | |
7 using System.Runtime.InteropServices; | |
8 using System.Security.Permissions; | |
9 using System.Windows.Forms; | |
10 using Microsoft.VisualStudio; | |
11 using Microsoft.VisualStudio.Designer.Interfaces; | |
12 using Microsoft.VisualStudio.OLE.Interop; | |
13 using Microsoft.VisualStudio.Shell.Interop; | |
14 | |
15 namespace Microsoft.VisualStudio.Project | |
16 { | |
17 | |
18 /// <summary> | |
19 /// The base class for property pages. | |
20 /// </summary> | |
21 [CLSCompliant(false), ComVisible(true)] | |
22 public abstract class SettingsPage : | |
23 LocalizableProperties, | |
24 IPropertyPage, | |
25 IDisposable | |
26 { | |
27 #region fields | |
28 private Panel panel; | |
29 private bool active; | |
30 private bool dirty; | |
31 private IPropertyPageSite site; | |
32 private ProjectNode project; | |
33 private ProjectConfig[] projectConfigs; | |
34 private IVSMDPropertyGrid grid; | |
35 private string name; | |
36 private static volatile object Mutex = new object(); | |
37 private bool isDisposed; | |
38 #endregion | |
39 | |
40 #region properties | |
41 | |
42 [Browsable(false)] | |
43 [AutomationBrowsable(false)] | |
44 public string Name | |
45 { | |
46 get | |
47 { | |
48 return this.name; | |
49 } | |
50 set | |
51 { | |
52 this.name = value; | |
53 } | |
54 } | |
55 | |
56 [Browsable(false)] | |
57 [AutomationBrowsable(false)] | |
58 public ProjectNode ProjectMgr | |
59 { | |
60 get | |
61 { | |
62 return this.project; | |
63 } | |
64 } | |
65 | |
66 protected IVSMDPropertyGrid Grid | |
67 { | |
68 get { return this.grid; } | |
69 } | |
70 | |
71 protected bool IsDirty | |
72 { | |
73 get | |
74 { | |
75 return this.dirty; | |
76 } | |
77 set | |
78 { | |
79 if(this.dirty != value) | |
80 { | |
81 this.dirty = value; | |
82 if(this.site != null) | |
83 site.OnStatusChange((uint)(this.
dirty ? PropPageStatus.Dirty : PropPageStatus.Clean)); | |
84 } | |
85 } | |
86 } | |
87 protected Panel ThePanel | |
88 { | |
89 get | |
90 { | |
91 return this.panel; | |
92 } | |
93 } | |
94 #endregion | |
95 | |
96 #region abstract methods | |
97 protected abstract void BindProperties(); | |
98 protected abstract int ApplyChanges(); | |
99 #endregion | |
100 | |
101 #region public methods | |
102 public object GetTypedConfigProperty(string name, Type type) | |
103 { | |
104 string value = GetConfigProperty(name); | |
105 if(string.IsNullOrEmpty(value)) return null; | |
106 | |
107 TypeConverter tc = TypeDescriptor.GetConverter(type); | |
108 return tc.ConvertFromInvariantString(value); | |
109 } | |
110 | |
111 public object GetTypedProperty(string name, Type type) | |
112 { | |
113 string value = GetProperty(name); | |
114 if(string.IsNullOrEmpty(value)) return null; | |
115 | |
116 TypeConverter tc = TypeDescriptor.GetConverter(type); | |
117 return tc.ConvertFromInvariantString(value); | |
118 } | |
119 | |
120 public string GetProperty(string propertyName) | |
121 { | |
122 if(this.ProjectMgr != null) | |
123 { | |
124 string property = this.ProjectMgr.BuildProject.G
lobalProperties[propertyName].Value; | |
125 | |
126 if(property != null) | |
127 { | |
128 return property; | |
129 } | |
130 } | |
131 | |
132 return String.Empty; | |
133 } | |
134 | |
135 // relative to active configuration. | |
136 public string GetConfigProperty(string propertyName) | |
137 { | |
138 if(this.ProjectMgr != null) | |
139 { | |
140 string unifiedResult = null; | |
141 bool cacheNeedReset = true; | |
142 | |
143 for(int i = 0; i < this.projectConfigs.Length; i
++) | |
144 { | |
145 ProjectConfig config = projectConfigs[i]
; | |
146 string property = config.GetConfiguratio
nProperty(propertyName, cacheNeedReset); | |
147 cacheNeedReset = false; | |
148 | |
149 if(property != null) | |
150 { | |
151 string text = property.Trim(); | |
152 | |
153 if(i == 0) | |
154 unifiedResult = text; | |
155 else if(unifiedResult != text) | |
156 return ""; // tristate v
alue is blank then | |
157 } | |
158 } | |
159 | |
160 return unifiedResult; | |
161 } | |
162 | |
163 return String.Empty; | |
164 } | |
165 | |
166 /// <summary> | |
167 /// Sets the value of a configuration dependent property. | |
168 /// If the attribute does not exist it is created. | |
169 /// If value is null it will be set to an empty string. | |
170 /// </summary> | |
171 /// <param name="name">property name.</param> | |
172 /// <param name="value">value of property</param> | |
173 public void SetConfigProperty(string name, string value) | |
174 { | |
175 CCITracing.TraceCall(); | |
176 if(value == null) | |
177 { | |
178 value = String.Empty; | |
179 } | |
180 | |
181 if(this.ProjectMgr != null) | |
182 { | |
183 for(int i = 0, n = this.projectConfigs.Length; i
< n; i++) | |
184 { | |
185 ProjectConfig config = projectConfigs[i]
; | |
186 | |
187 config.SetConfigurationProperty(name, va
lue); | |
188 } | |
189 | |
190 this.ProjectMgr.SetProjectFileDirty(true); | |
191 } | |
192 } | |
193 | |
194 #endregion | |
195 | |
196 #region IPropertyPage methods. | |
197 public virtual void Activate(IntPtr parent, RECT[] pRect, int bM
odal) | |
198 { | |
199 if(this.panel == null) | |
200 { | |
201 this.panel = new Panel(); | |
202 this.panel.Size = new Size(pRect[0].right - pRec
t[0].left, pRect[0].bottom - pRect[0].top); | |
203 this.panel.Text = "Settings";// TODO localizatio
n | |
204 this.panel.Visible = false; | |
205 this.panel.Size = new Size(550, 300); | |
206 this.panel.CreateControl(); | |
207 NativeMethods.SetParent(this.panel.Handle, paren
t); | |
208 } | |
209 | |
210 if(this.grid == null && this.project != null && this.pro
ject.Site != null) | |
211 { | |
212 IVSMDPropertyBrowser pb = this.project.Site.GetS
ervice(typeof(IVSMDPropertyBrowser)) as IVSMDPropertyBrowser; | |
213 this.grid = pb.CreatePropertyGrid(); | |
214 } | |
215 | |
216 if(this.grid != null) | |
217 { | |
218 this.active = true; | |
219 | |
220 | |
221 Control cGrid = Control.FromHandle(new IntPtr(th
is.grid.Handle)); | |
222 | |
223 cGrid.Parent = Control.FromHandle(parent);//this
.panel; | |
224 cGrid.Size = new Size(544, 294); | |
225 cGrid.Location = new Point(3, 3); | |
226 cGrid.Visible = true; | |
227 this.grid.SetOption(_PROPERTYGRIDOPTION.PGOPT_TO
OLBAR, false); | |
228 this.grid.GridSort = _PROPERTYGRIDSORT.PGSORT_CA
TEGORIZED | _PROPERTYGRIDSORT.PGSORT_ALPHABETICAL; | |
229 NativeMethods.SetParent(new IntPtr(this.grid.Han
dle), this.panel.Handle); | |
230 UpdateObjects(); | |
231 } | |
232 } | |
233 | |
234 public virtual int Apply() | |
235 { | |
236 if(IsDirty) | |
237 { | |
238 return this.ApplyChanges(); | |
239 } | |
240 return VSConstants.S_OK; | |
241 } | |
242 | |
243 public virtual void Deactivate() | |
244 { | |
245 if(null != this.panel) | |
246 { | |
247 this.panel.Dispose(); | |
248 this.panel = null; | |
249 } | |
250 this.active = false; | |
251 } | |
252 | |
253 public virtual void GetPageInfo(PROPPAGEINFO[] arrInfo) | |
254 { | |
255 PROPPAGEINFO info = new PROPPAGEINFO(); | |
256 | |
257 info.cb = (uint)Marshal.SizeOf(typeof(PROPPAGEINFO)); | |
258 info.dwHelpContext = 0; | |
259 info.pszDocString = null; | |
260 info.pszHelpFile = null; | |
261 info.pszTitle = this.name; | |
262 info.SIZE.cx = 550; | |
263 info.SIZE.cy = 300; | |
264 arrInfo[0] = info; | |
265 } | |
266 | |
267 public virtual void Help(string helpDir) | |
268 { | |
269 } | |
270 | |
271 public virtual int IsPageDirty() | |
272 { | |
273 // Note this returns an HRESULT not a Bool. | |
274 return (IsDirty ? (int)VSConstants.S_OK : (int)VSConstan
ts.S_FALSE); | |
275 } | |
276 | |
277 public virtual void Move(RECT[] arrRect) | |
278 { | |
279 RECT r = arrRect[0]; | |
280 | |
281 this.panel.Location = new Point(r.left, r.top); | |
282 this.panel.Size = new Size(r.right - r.left, r.bottom -
r.top); | |
283 } | |
284 | |
285 public virtual void SetObjects(uint count, object[] punk) | |
286 { | |
287 if(count > 0) | |
288 { | |
289 if(punk[0] is ProjectConfig) | |
290 { | |
291 ArrayList configs = new ArrayList(); | |
292 | |
293 for(int i = 0; i < count; i++) | |
294 { | |
295 ProjectConfig config = (ProjectC
onfig)punk[i]; | |
296 | |
297 if(this.project == null) | |
298 { | |
299 this.project = config.Pr
ojectMgr; | |
300 } | |
301 | |
302 configs.Add(config); | |
303 } | |
304 | |
305 this.projectConfigs = (ProjectConfig[])c
onfigs.ToArray(typeof(ProjectConfig)); | |
306 } | |
307 else if(punk[0] is NodeProperties) | |
308 { | |
309 if(this.project == null) | |
310 { | |
311 this.project = (punk[0] as NodeP
roperties).Node.ProjectMgr; | |
312 } | |
313 | |
314 System.Collections.Generic.Dictionary<st
ring, ProjectConfig> configsMap = new System.Collections.Generic.Dictionary<stri
ng, ProjectConfig>(); | |
315 | |
316 for(int i = 0; i < count; i++) | |
317 { | |
318 NodeProperties property = (NodeP
roperties)punk[i]; | |
319 IVsCfgProvider provider; | |
320 ErrorHandler.ThrowOnFailure(prop
erty.Node.ProjectMgr.GetCfgProvider(out provider)); | |
321 uint[] expected = new uint[1]; | |
322 ErrorHandler.ThrowOnFailure(prov
ider.GetCfgs(0, null, expected, null)); | |
323 if(expected[0] > 0) | |
324 { | |
325 ProjectConfig[] configs
= new ProjectConfig[expected[0]]; | |
326 uint[] actual = new uint
[1]; | |
327 ErrorHandler.ThrowOnFail
ure(provider.GetCfgs(expected[0], configs, actual, null)); | |
328 | |
329 foreach(ProjectConfig co
nfig in configs) | |
330 { | |
331 if(!configsMap.C
ontainsKey(config.ConfigName)) | |
332 { | |
333 configsM
ap.Add(config.ConfigName, config); | |
334 } | |
335 } | |
336 } | |
337 } | |
338 | |
339 if(configsMap.Count > 0) | |
340 { | |
341 if(this.projectConfigs == null) | |
342 { | |
343 this.projectConfigs = ne
w ProjectConfig[configsMap.Keys.Count]; | |
344 } | |
345 configsMap.Values.CopyTo(this.pr
ojectConfigs, 0); | |
346 } | |
347 } | |
348 } | |
349 else | |
350 { | |
351 this.project = null; | |
352 } | |
353 | |
354 if(this.active && this.project != null) | |
355 { | |
356 UpdateObjects(); | |
357 } | |
358 } | |
359 | |
360 | |
361 public virtual void SetPageSite(IPropertyPageSite theSite) | |
362 { | |
363 this.site = theSite; | |
364 } | |
365 | |
366 public virtual void Show(uint cmd) | |
367 { | |
368 this.panel.Visible = true; // TODO: pass SW_SHOW* flags
through | |
369 this.panel.Show(); | |
370 } | |
371 | |
372 public virtual int TranslateAccelerator(MSG[] arrMsg) | |
373 { | |
374 MSG msg = arrMsg[0]; | |
375 | |
376 if((msg.message < NativeMethods.WM_KEYFIRST || msg.messa
ge > NativeMethods.WM_KEYLAST) && (msg.message < NativeMethods.WM_MOUSEFIRST ||
msg.message > NativeMethods.WM_MOUSELAST)) | |
377 return 1; | |
378 | |
379 return (NativeMethods.IsDialogMessageA(this.panel.Handle
, ref msg)) ? 0 : 1; | |
380 } | |
381 | |
382 #endregion | |
383 | |
384 #region helper methods | |
385 | |
386 protected ProjectConfig[] GetProjectConfigurations() | |
387 { | |
388 return this.projectConfigs; | |
389 } | |
390 | |
391 protected void UpdateObjects() | |
392 { | |
393 if(this.projectConfigs != null && this.project != null) | |
394 { | |
395 // Demand unmanaged permissions in order to acce
ss unmanaged memory. | |
396 new SecurityPermission(SecurityPermissionFlag.Un
managedCode).Demand(); | |
397 | |
398 IntPtr p = Marshal.GetIUnknownForObject(this); | |
399 IntPtr ppUnk = Marshal.AllocCoTaskMem(Marshal.Si
zeOf(typeof(IntPtr))); | |
400 try | |
401 { | |
402 Marshal.WriteIntPtr(ppUnk, p); | |
403 this.BindProperties(); | |
404 // BUGBUG -- this is really bad casting
a pointer to "int"... | |
405 this.grid.SetSelectedObjects(1, ppUnk.To
Int32()); | |
406 this.grid.Refresh(); | |
407 } | |
408 finally | |
409 { | |
410 if(ppUnk != IntPtr.Zero) | |
411 { | |
412 Marshal.FreeCoTaskMem(ppUnk); | |
413 } | |
414 if(p != IntPtr.Zero) | |
415 { | |
416 Marshal.Release(p); | |
417 } | |
418 } | |
419 } | |
420 } | |
421 #endregion | |
422 | |
423 #region IDisposable Members | |
424 | |
425 /// <summary> | |
426 /// Performs application-defined tasks associated with freeing,
releasing, or resetting unmanaged resources. | |
427 /// </summary> | |
428 public void Dispose() | |
429 { | |
430 this.Dispose(true); | |
431 GC.SuppressFinalize(this); | |
432 } | |
433 | |
434 #endregion | |
435 | |
436 private void Dispose(bool disposing) | |
437 { | |
438 if(!this.isDisposed) | |
439 { | |
440 lock(Mutex) | |
441 { | |
442 if(disposing) | |
443 { | |
444 this.panel.Dispose(); | |
445 } | |
446 | |
447 this.isDisposed = true; | |
448 } | |
449 } | |
450 } | |
451 } | |
452 } | |
OLD | NEW |