mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 20:39:01 +00:00
524 lines
17 KiB
C#
524 lines
17 KiB
C#
/********************************************************************************************
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
Microsoft Public License:
|
|
|
|
This license governs use of the accompanying software. If you use the software, you
|
|
accept this license. If you do not accept the license, do not use the software.
|
|
|
|
1. Definitions
|
|
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
|
|
same meaning here as under U.S. copyright law.
|
|
A "contribution" is the original software, or any additions or changes to the software.
|
|
A "contributor" is any person that distributes its contribution under this license.
|
|
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
|
|
|
|
2. Grant of Rights
|
|
(A) Copyright Grant- Subject to the terms of this license, including the license conditions
|
|
and limitations in section 3, each contributor grants you a non-exclusive, worldwide,
|
|
royalty-free copyright license to reproduce its contribution, prepare derivative works of
|
|
its contribution, and distribute its contribution or any derivative works that you create.
|
|
(B) Patent Grant- Subject to the terms of this license, including the license conditions
|
|
and limitations in section 3, each contributor grants you a non-exclusive, worldwide,
|
|
royalty-free license under its licensed patents to make, have made, use, sell, offer for
|
|
sale, import, and/or otherwise dispose of its contribution in the software or derivative
|
|
works of the contribution in the software.
|
|
|
|
3. Conditions and Limitations
|
|
(A) No Trademark License- This license does not grant you rights to use any contributors'
|
|
name, logo, or trademarks.
|
|
(B) If you bring a patent claim against any contributor over patents that you claim are
|
|
infringed by the software, your patent license from such contributor to the software ends
|
|
automatically.
|
|
(C) If you distribute any portion of the software, you must retain all copyright, patent,
|
|
trademark, and attribution notices that are present in the software.
|
|
(D) If you distribute any portion of the software in source code form, you may do so only
|
|
under this license by including a complete copy of this license with your distribution.
|
|
If you distribute any portion of the software in compiled or object code form, you may only
|
|
do so under a license that complies with this license.
|
|
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give
|
|
no express warranties, guarantees or conditions. You may have additional consumer rights
|
|
under your local laws which this license cannot change. To the extent permitted under your
|
|
local laws, the contributors exclude the implied warranties of merchantability, fitness for
|
|
a particular purpose and non-infringement.
|
|
|
|
********************************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Globalization;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Permissions;
|
|
using System.Windows.Forms;
|
|
using Microsoft.VisualStudio.Designer.Interfaces;
|
|
using Microsoft.VisualStudio.OLE.Interop;
|
|
using Microsoft.VisualStudio.Shell.Interop;
|
|
|
|
namespace Microsoft.VisualStudio.Project
|
|
{
|
|
|
|
/// <summary>
|
|
/// The base class for property pages.
|
|
/// </summary>
|
|
|
|
public abstract class SettingsPage :
|
|
LocalizableProperties,
|
|
IPropertyPage,
|
|
IDisposable
|
|
{
|
|
#region fields
|
|
private Panel panel;
|
|
private bool active;
|
|
private bool dirty;
|
|
private IPropertyPageSite site;
|
|
private ProjectNode project;
|
|
private ProjectConfig[] projectConfigs;
|
|
private IVSMDPropertyGrid grid;
|
|
private string name;
|
|
private static volatile object Mutex = new object();
|
|
private bool isDisposed;
|
|
#endregion
|
|
|
|
#region properties
|
|
|
|
[Browsable(false)]
|
|
[AutomationBrowsable(false)]
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return this.name;
|
|
}
|
|
set
|
|
{
|
|
this.name = value;
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[AutomationBrowsable(false)]
|
|
public ProjectNode ProjectMgr
|
|
{
|
|
get
|
|
{
|
|
return this.project;
|
|
}
|
|
}
|
|
|
|
protected IVSMDPropertyGrid Grid
|
|
{
|
|
get { return this.grid; }
|
|
}
|
|
|
|
protected bool IsDirty
|
|
{
|
|
get
|
|
{
|
|
return this.dirty;
|
|
}
|
|
set
|
|
{
|
|
if(this.dirty != value)
|
|
{
|
|
this.dirty = value;
|
|
if(this.site != null)
|
|
site.OnStatusChange((uint)(this.dirty ? PropPageStatus.Dirty : PropPageStatus.Clean));
|
|
}
|
|
}
|
|
}
|
|
protected Panel ThePanel
|
|
{
|
|
get
|
|
{
|
|
return this.panel;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region abstract methods
|
|
protected abstract void BindProperties();
|
|
protected abstract int ApplyChanges();
|
|
#endregion
|
|
|
|
#region public methods
|
|
public object GetTypedConfigProperty(string name, Type type)
|
|
{
|
|
string value = GetConfigProperty(name);
|
|
if(string.IsNullOrEmpty(value)) return null;
|
|
|
|
TypeConverter tc = TypeDescriptor.GetConverter(type);
|
|
return tc.ConvertFromInvariantString(value);
|
|
}
|
|
|
|
public object GetTypedProperty(string name, Type type)
|
|
{
|
|
string value = GetProperty(name);
|
|
if(string.IsNullOrEmpty(value)) return null;
|
|
|
|
TypeConverter tc = TypeDescriptor.GetConverter(type);
|
|
return tc.ConvertFromInvariantString(value);
|
|
}
|
|
|
|
public string GetProperty(string propertyName)
|
|
{
|
|
if(this.ProjectMgr != null)
|
|
{
|
|
string property;
|
|
bool found = this.ProjectMgr.BuildProject.GlobalProperties.TryGetValue(propertyName, out property);
|
|
|
|
if(found)
|
|
{
|
|
return property;
|
|
}
|
|
}
|
|
|
|
return String.Empty;
|
|
}
|
|
|
|
// relative to active configuration.
|
|
public string GetConfigProperty(string propertyName)
|
|
{
|
|
if(this.ProjectMgr != null)
|
|
{
|
|
string unifiedResult = null;
|
|
bool cacheNeedReset = true;
|
|
|
|
for(int i = 0; i < this.projectConfigs.Length; i++)
|
|
{
|
|
ProjectConfig config = projectConfigs[i];
|
|
string property = config.GetConfigurationProperty(propertyName, cacheNeedReset);
|
|
cacheNeedReset = false;
|
|
|
|
if(property != null)
|
|
{
|
|
string text = property.Trim();
|
|
|
|
if(i == 0)
|
|
unifiedResult = text;
|
|
else if(unifiedResult != text)
|
|
return ""; // tristate value is blank then
|
|
}
|
|
}
|
|
|
|
return unifiedResult;
|
|
}
|
|
|
|
return String.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the value of a configuration dependent property.
|
|
/// If the attribute does not exist it is created.
|
|
/// If value is null it will be set to an empty string.
|
|
/// </summary>
|
|
/// <param name="name">property name.</param>
|
|
/// <param name="value">value of property</param>
|
|
public void SetConfigProperty(string name, string value)
|
|
{
|
|
CCITracing.TraceCall();
|
|
if(value == null)
|
|
{
|
|
value = String.Empty;
|
|
}
|
|
|
|
if(this.ProjectMgr != null)
|
|
{
|
|
for(int i = 0, n = this.projectConfigs.Length; i < n; i++)
|
|
{
|
|
ProjectConfig config = projectConfigs[i];
|
|
|
|
config.SetConfigurationProperty(name, value);
|
|
}
|
|
|
|
this.ProjectMgr.SetProjectFileDirty(true);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IPropertyPage methods.
|
|
public virtual void Activate(IntPtr parent, RECT[] pRect, int bModal)
|
|
{
|
|
if(this.panel == null)
|
|
{
|
|
if (pRect == null)
|
|
{
|
|
throw new ArgumentNullException("pRect");
|
|
}
|
|
|
|
this.panel = new Panel();
|
|
this.panel.Size = new Size(pRect[0].right - pRect[0].left, pRect[0].bottom - pRect[0].top);
|
|
this.panel.Text = SR.GetString(SR.Settings, CultureInfo.CurrentUICulture);
|
|
this.panel.Visible = false;
|
|
this.panel.Size = new Size(550, 300);
|
|
this.panel.CreateControl();
|
|
NativeMethods.SetParent(this.panel.Handle, parent);
|
|
}
|
|
|
|
if(this.grid == null && this.project != null && this.project.Site != null)
|
|
{
|
|
IVSMDPropertyBrowser pb = this.project.Site.GetService(typeof(IVSMDPropertyBrowser)) as IVSMDPropertyBrowser;
|
|
this.grid = pb.CreatePropertyGrid();
|
|
}
|
|
|
|
if(this.grid != null)
|
|
{
|
|
this.active = true;
|
|
|
|
|
|
Control cGrid = Control.FromHandle(new IntPtr(this.grid.Handle));
|
|
|
|
cGrid.Parent = Control.FromHandle(parent);//this.panel;
|
|
cGrid.Size = new Size(544, 294);
|
|
cGrid.Location = new Point(3, 3);
|
|
cGrid.Visible = true;
|
|
this.grid.SetOption(_PROPERTYGRIDOPTION.PGOPT_TOOLBAR, false);
|
|
this.grid.GridSort = _PROPERTYGRIDSORT.PGSORT_CATEGORIZED | _PROPERTYGRIDSORT.PGSORT_ALPHABETICAL;
|
|
NativeMethods.SetParent(new IntPtr(this.grid.Handle), this.panel.Handle);
|
|
UpdateObjects();
|
|
}
|
|
}
|
|
|
|
public virtual int Apply()
|
|
{
|
|
if(IsDirty)
|
|
{
|
|
return this.ApplyChanges();
|
|
}
|
|
return VSConstants.S_OK;
|
|
}
|
|
|
|
public virtual void Deactivate()
|
|
{
|
|
if(null != this.panel)
|
|
{
|
|
this.panel.Dispose();
|
|
this.panel = null;
|
|
}
|
|
this.active = false;
|
|
}
|
|
|
|
public virtual void GetPageInfo(PROPPAGEINFO[] arrInfo)
|
|
{
|
|
if (arrInfo == null)
|
|
{
|
|
throw new ArgumentNullException("arrInfo");
|
|
}
|
|
|
|
PROPPAGEINFO info = new PROPPAGEINFO();
|
|
|
|
info.cb = (uint)Marshal.SizeOf(typeof(PROPPAGEINFO));
|
|
info.dwHelpContext = 0;
|
|
info.pszDocString = null;
|
|
info.pszHelpFile = null;
|
|
info.pszTitle = this.name;
|
|
info.SIZE.cx = 550;
|
|
info.SIZE.cy = 300;
|
|
arrInfo[0] = info;
|
|
}
|
|
|
|
public virtual void Help(string helpDir)
|
|
{
|
|
}
|
|
|
|
public virtual int IsPageDirty()
|
|
{
|
|
// Note this returns an HRESULT not a Bool.
|
|
return (IsDirty ? (int)VSConstants.S_OK : (int)VSConstants.S_FALSE);
|
|
}
|
|
|
|
public virtual void Move(RECT[] arrRect)
|
|
{
|
|
if (arrRect == null)
|
|
{
|
|
throw new ArgumentNullException("arrRect");
|
|
}
|
|
|
|
RECT r = arrRect[0];
|
|
|
|
this.panel.Location = new Point(r.left, r.top);
|
|
this.panel.Size = new Size(r.right - r.left, r.bottom - r.top);
|
|
}
|
|
|
|
public virtual void SetObjects(uint count, object[] punk)
|
|
{
|
|
if (punk == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(count > 0)
|
|
{
|
|
if(punk[0] is ProjectConfig)
|
|
{
|
|
ArrayList configs = new ArrayList();
|
|
|
|
for(int i = 0; i < count; i++)
|
|
{
|
|
ProjectConfig config = (ProjectConfig)punk[i];
|
|
|
|
if(this.project == null || (this.project != (punk[0] as ProjectConfig).ProjectMgr))
|
|
{
|
|
this.project = config.ProjectMgr;
|
|
}
|
|
|
|
configs.Add(config);
|
|
}
|
|
|
|
this.projectConfigs = (ProjectConfig[])configs.ToArray(typeof(ProjectConfig));
|
|
}
|
|
else if(punk[0] is NodeProperties)
|
|
{
|
|
if (this.project == null || (this.project != (punk[0] as NodeProperties).Node.ProjectMgr))
|
|
{
|
|
this.project = (punk[0] as NodeProperties).Node.ProjectMgr;
|
|
}
|
|
|
|
System.Collections.Generic.Dictionary<string, ProjectConfig> configsMap = new System.Collections.Generic.Dictionary<string, ProjectConfig>();
|
|
|
|
for(int i = 0; i < count; i++)
|
|
{
|
|
NodeProperties property = (NodeProperties)punk[i];
|
|
IVsCfgProvider provider;
|
|
ErrorHandler.ThrowOnFailure(property.Node.ProjectMgr.GetCfgProvider(out provider));
|
|
uint[] expected = new uint[1];
|
|
ErrorHandler.ThrowOnFailure(provider.GetCfgs(0, null, expected, null));
|
|
if(expected[0] > 0)
|
|
{
|
|
ProjectConfig[] configs = new ProjectConfig[expected[0]];
|
|
uint[] actual = new uint[1];
|
|
ErrorHandler.ThrowOnFailure(provider.GetCfgs(expected[0], configs, actual, null));
|
|
|
|
foreach(ProjectConfig config in configs)
|
|
{
|
|
if(!configsMap.ContainsKey(config.ConfigName))
|
|
{
|
|
configsMap.Add(config.ConfigName, config);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(configsMap.Count > 0)
|
|
{
|
|
if(this.projectConfigs == null)
|
|
{
|
|
this.projectConfigs = new ProjectConfig[configsMap.Keys.Count];
|
|
}
|
|
configsMap.Values.CopyTo(this.projectConfigs, 0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.project = null;
|
|
}
|
|
|
|
if(this.active && this.project != null)
|
|
{
|
|
UpdateObjects();
|
|
}
|
|
}
|
|
|
|
|
|
public virtual void SetPageSite(IPropertyPageSite theSite)
|
|
{
|
|
this.site = theSite;
|
|
}
|
|
|
|
public virtual void Show(uint cmd)
|
|
{
|
|
this.panel.Visible = true; // TODO: pass SW_SHOW* flags through
|
|
this.panel.Show();
|
|
}
|
|
|
|
public virtual int TranslateAccelerator(MSG[] arrMsg)
|
|
{
|
|
if (arrMsg == null)
|
|
{
|
|
throw new ArgumentNullException("arrMsg");
|
|
}
|
|
|
|
MSG msg = arrMsg[0];
|
|
|
|
if((msg.message < NativeMethods.WM_KEYFIRST || msg.message > NativeMethods.WM_KEYLAST) && (msg.message < NativeMethods.WM_MOUSEFIRST || msg.message > NativeMethods.WM_MOUSELAST))
|
|
return 1;
|
|
|
|
return (NativeMethods.IsDialogMessageA(this.panel.Handle, ref msg)) ? 0 : 1;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region helper methods
|
|
|
|
protected ProjectConfig[] GetProjectConfigurations()
|
|
{
|
|
return this.projectConfigs;
|
|
}
|
|
|
|
protected void UpdateObjects()
|
|
{
|
|
if(this.projectConfigs != null && this.project != null)
|
|
{
|
|
// Demand unmanaged permissions in order to access unmanaged memory.
|
|
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
|
|
|
|
IntPtr p = Marshal.GetIUnknownForObject(this);
|
|
IntPtr ppUnk = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)));
|
|
try
|
|
{
|
|
Marshal.WriteIntPtr(ppUnk, p);
|
|
this.BindProperties();
|
|
// BUGBUG -- this is really bad casting a pointer to "int"...
|
|
this.grid.SetSelectedObjects(1, ppUnk.ToInt32());
|
|
this.grid.Refresh();
|
|
}
|
|
finally
|
|
{
|
|
if(ppUnk != IntPtr.Zero)
|
|
{
|
|
Marshal.FreeCoTaskMem(ppUnk);
|
|
}
|
|
if(p != IntPtr.Zero)
|
|
{
|
|
Marshal.Release(p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region IDisposable Members
|
|
|
|
/// <summary>
|
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
this.Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void Dispose(bool disposing)
|
|
{
|
|
if(!this.isDisposed)
|
|
{
|
|
lock(Mutex)
|
|
{
|
|
if(disposing)
|
|
{
|
|
this.panel.Dispose();
|
|
}
|
|
|
|
this.isDisposed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|