Replaced the old VS templates with ones that offer more flexiblity. Started replacing the Content Project for the samples with our custom project type. Inlcuded a basic not yet working AssimpImporter.
348 lines
14 KiB
C#
348 lines
14 KiB
C#
/* ****************************************************************************
|
|
*
|
|
* Copyright (c) Microsoft Corporation.
|
|
*
|
|
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
|
* copy of the license can be found in the License.html file at the root of this distribution. If
|
|
* you cannot locate the Apache License, Version 2.0, please send an email to
|
|
* vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
|
* by the terms of the Apache License, Version 2.0.
|
|
*
|
|
* You must not remove this notice, or any other, from this software.
|
|
*
|
|
* ***************************************************************************/
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using Microsoft.VisualStudio;
|
|
using Microsoft.VisualStudio.ComponentModelHost;
|
|
using Microsoft.VisualStudio.Editor;
|
|
using Microsoft.VisualStudio.OLE.Interop;
|
|
using Microsoft.VisualStudio.Shell;
|
|
using Microsoft.VisualStudio.Shell.Interop;
|
|
using Microsoft.VisualStudio.Text;
|
|
using Microsoft.VisualStudio.Text.Editor;
|
|
using Microsoft.VisualStudio.TextManager.Interop;
|
|
using Microsoft.VisualStudio.Project.Automation;
|
|
using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID;
|
|
using VSConstants = Microsoft.VisualStudio.VSConstants;
|
|
|
|
namespace Microsoft.VisualStudio.Project {
|
|
public class CommonFileNode : FileNode {
|
|
private OAVSProjectItem _vsProjectItem;
|
|
private CommonProjectNode _project;
|
|
|
|
public CommonFileNode(CommonProjectNode root, ProjectElement e)
|
|
: base(root, e) {
|
|
_project = root;
|
|
}
|
|
|
|
#region properties
|
|
/// <summary>
|
|
/// Returns bool indicating whether this node is of subtype "Form"
|
|
/// </summary>
|
|
public bool IsFormSubType {
|
|
get {
|
|
string result = this.ItemNode.GetMetadata(ProjectFileConstants.SubType);
|
|
if (!String.IsNullOrEmpty(result) && string.Compare(result, ProjectFileAttributeValue.Form, true, CultureInfo.InvariantCulture) == 0)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Returns the SubType of a dynamic FileNode. It is
|
|
/// </summary>
|
|
public string SubType {
|
|
get {
|
|
return this.ItemNode.GetMetadata(ProjectFileConstants.SubType);
|
|
}
|
|
set {
|
|
this.ItemNode.SetMetadata(ProjectFileConstants.SubType, value);
|
|
}
|
|
}
|
|
|
|
public VSLangProj.VSProjectItem VSProjectItem {
|
|
get {
|
|
if (null == _vsProjectItem) {
|
|
_vsProjectItem = new OAVSProjectItem(this);
|
|
}
|
|
return _vsProjectItem;
|
|
}
|
|
}
|
|
|
|
#if DEV11_OR_LATER
|
|
public override __VSPROVISIONALVIEWINGSTATUS ProvisionalViewingStatus {
|
|
get {
|
|
return __VSPROVISIONALVIEWINGSTATUS.PVS_Enabled;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endregion
|
|
|
|
#region overridden properties
|
|
|
|
public override object Object {
|
|
get {
|
|
return this.VSProjectItem;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region overridden methods
|
|
|
|
public override int ImageIndex {
|
|
get {
|
|
if (ItemNode.IsExcluded) {
|
|
return (int)ProjectNode.ImageName.ExcludedFile;
|
|
} else if (!File.Exists(Url)) {
|
|
return (int)ProjectNode.ImageName.MissingFile;
|
|
} else if (IsFormSubType) {
|
|
return (int)ProjectNode.ImageName.WindowsForm;
|
|
} else if (this._project.IsCodeFile(FileName)) {
|
|
if (CommonUtils.IsSamePath(this.Url, _project.GetStartupFile())) {
|
|
return CommonProjectNode.ImageOffset + (int)CommonImageName.StartupFile;
|
|
} else {
|
|
return CommonProjectNode.ImageOffset + (int)CommonImageName.File;
|
|
}
|
|
}
|
|
return base.ImageIndex;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Open a file depending on the SubType property associated with the file item in the project file
|
|
/// </summary>
|
|
protected override void DoDefaultAction() {
|
|
FileDocumentManager manager = this.GetDocumentManager() as FileDocumentManager;
|
|
Debug.Assert(manager != null, "Could not get the FileDocumentManager");
|
|
|
|
Guid viewGuid =
|
|
(IsFormSubType ? VSConstants.LOGVIEWID_Designer : VSConstants.LOGVIEWID_Code);
|
|
IVsWindowFrame frame;
|
|
manager.Open(false, false, viewGuid, out frame, WindowFrameShowAction.Show);
|
|
}
|
|
|
|
private static Guid CLSID_VsTextBuffer = new Guid("{8E7B96A8-E33D-11d0-A6D5-00C04FB67F6A}");
|
|
|
|
/// <summary>
|
|
/// Gets the text buffer for the file opening the document if necessary.
|
|
/// </summary>
|
|
public ITextBuffer GetTextBuffer() {
|
|
if (UIThread.Instance.IsUIThread) {
|
|
// http://pytools.codeplex.com/workitem/672
|
|
// When we FindAndLockDocument we marshal on the main UI thread, and the docdata we get
|
|
// back is marshalled back so that we'll marshal any calls on it back. When we pass it
|
|
// into IVsEditorAdaptersFactoryService we don't go through a COM boundary (it's a managed
|
|
// call) and we therefore don't get the marshaled value, and it doesn't know what we're
|
|
// talking about. So run the whole operation on the UI thread.
|
|
return GetTextBufferOnUIThread();
|
|
}
|
|
|
|
ITextBuffer res = null;
|
|
UIThread.Instance.RunSync(
|
|
() => {
|
|
res = GetTextBufferOnUIThread();
|
|
}
|
|
);
|
|
return res;
|
|
}
|
|
|
|
private ITextBuffer GetTextBufferOnUIThread() {
|
|
IVsTextManager textMgr = (IVsTextManager)GetService(typeof(SVsTextManager));
|
|
var model = GetService(typeof(SComponentModel)) as IComponentModel;
|
|
var adapter = model.GetService<IVsEditorAdaptersFactoryService>();
|
|
uint itemid;
|
|
|
|
IVsRunningDocumentTable rdt = ProjectMgr.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable;
|
|
if (rdt != null) {
|
|
IVsHierarchy hier;
|
|
IVsPersistDocData persistDocData;
|
|
uint cookie;
|
|
bool docInRdt = true;
|
|
IntPtr docData = IntPtr.Zero;
|
|
int hr = NativeMethods.E_FAIL;
|
|
try {
|
|
//Getting a read lock on the document. Must be released later.
|
|
hr = rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_ReadLock, GetMkDocument(), out hier, out itemid, out docData, out cookie);
|
|
if (ErrorHandler.Failed(hr) || docData == IntPtr.Zero) {
|
|
Guid iid = VSConstants.IID_IUnknown;
|
|
cookie = 0;
|
|
docInRdt = false;
|
|
ILocalRegistry localReg = this.ProjectMgr.GetService(typeof(SLocalRegistry)) as ILocalRegistry;
|
|
ErrorHandler.ThrowOnFailure(localReg.CreateInstance(CLSID_VsTextBuffer, null, ref iid, (uint)CLSCTX.CLSCTX_INPROC_SERVER, out docData));
|
|
}
|
|
persistDocData = Marshal.GetObjectForIUnknown(docData) as IVsPersistDocData;
|
|
} finally {
|
|
if (docData != IntPtr.Zero) {
|
|
Marshal.Release(docData);
|
|
}
|
|
}
|
|
|
|
//Try to get the Text lines
|
|
IVsTextLines srpTextLines = persistDocData as IVsTextLines;
|
|
if (srpTextLines == null) {
|
|
// Try getting a text buffer provider first
|
|
IVsTextBufferProvider srpTextBufferProvider = persistDocData as IVsTextBufferProvider;
|
|
if (srpTextBufferProvider != null) {
|
|
hr = srpTextBufferProvider.GetTextBuffer(out srpTextLines);
|
|
}
|
|
}
|
|
|
|
// Unlock the document in the RDT if necessary
|
|
if (docInRdt && rdt != null) {
|
|
ErrorHandler.ThrowOnFailure(rdt.UnlockDocument((uint)(_VSRDTFLAGS.RDT_ReadLock | _VSRDTFLAGS.RDT_Unlock_NoSave), cookie));
|
|
}
|
|
|
|
if (srpTextLines != null) {
|
|
return adapter.GetDocumentBuffer(srpTextLines);
|
|
}
|
|
}
|
|
|
|
IWpfTextView view = GetTextView();
|
|
|
|
return view.TextBuffer;
|
|
}
|
|
|
|
public IWpfTextView GetTextView() {
|
|
var model = GetService(typeof(SComponentModel)) as IComponentModel;
|
|
var adapter = model.GetService<IVsEditorAdaptersFactoryService>();
|
|
|
|
IVsTextView viewAdapter;
|
|
uint itemid;
|
|
IVsUIHierarchy hierarchy;
|
|
IVsWindowFrame pWindowFrame;
|
|
|
|
VsShellUtilities.OpenDocument(
|
|
ProjectMgr.Site,
|
|
this.GetMkDocument(),
|
|
Guid.Empty,
|
|
out hierarchy,
|
|
out itemid,
|
|
out pWindowFrame,
|
|
out viewAdapter);
|
|
|
|
ErrorHandler.ThrowOnFailure(pWindowFrame.Show());
|
|
return adapter.GetWpfTextView(viewAdapter);
|
|
}
|
|
|
|
public new CommonProjectNode ProjectMgr {
|
|
get {
|
|
return (CommonProjectNode)base.ProjectMgr;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the exclude from project command.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override int ExcludeFromProject() {
|
|
Debug.Assert(this.ProjectMgr != null, "The project item " + this.ToString() + " has not been initialised correctly. It has a null ProjectMgr");
|
|
if (!ProjectMgr.QueryEditProjectFile(false) ||
|
|
!ProjectMgr.Tracker.CanRemoveItems(new[] { Url }, new [] { VSQUERYREMOVEFILEFLAGS.VSQUERYREMOVEFILEFLAGS_NoFlags })) {
|
|
return VSConstants.E_FAIL;
|
|
}
|
|
|
|
ResetNodeProperties();
|
|
ItemNode.RemoveFromProjectFile();
|
|
if (!File.Exists(Url)) {
|
|
Parent.RemoveChild(this);
|
|
ProjectMgr.OnItemDeleted(this);
|
|
} else {
|
|
ItemNode = new AllFilesProjectElement(Url, ItemNode.ItemTypeName, ProjectMgr);
|
|
if (!ProjectMgr.IsShowingAllFiles) {
|
|
IsVisible = false;
|
|
ProjectMgr.OnInvalidateItems(Parent);
|
|
}
|
|
ProjectMgr.ReDrawNode(this, UIHierarchyElement.Icon);
|
|
ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_IsNonMemberItem, 0);
|
|
}
|
|
return VSConstants.S_OK;
|
|
}
|
|
|
|
public override int IncludeInProject(bool includeChildren) {
|
|
if (Parent.ItemNode != null && Parent.ItemNode.IsExcluded) {
|
|
// if our parent is excluded it needs to first be included
|
|
int hr = Parent.IncludeInProject(false);
|
|
if (ErrorHandler.Failed(hr)) {
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
if (!ProjectMgr.QueryEditProjectFile(false) ||
|
|
!ProjectMgr.Tracker.CanAddItems(new[] { Url }, new[] { VSQUERYADDFILEFLAGS.VSQUERYADDFILEFLAGS_NoFlags })) {
|
|
return VSConstants.E_FAIL;
|
|
}
|
|
|
|
ResetNodeProperties();
|
|
ItemNode = ProjectMgr.AddFileToMsBuild(Url);
|
|
IsVisible = true;
|
|
ProjectMgr.OnInvalidateItems(Parent);
|
|
ProjectMgr.ReDrawNode(this, UIHierarchyElement.Icon);
|
|
ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_IsNonMemberItem, 0);
|
|
return VSConstants.S_OK;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the menuitems
|
|
/// </summary>
|
|
public override int QueryStatusOnNode(Guid guidCmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) {
|
|
if (guidCmdGroup == Microsoft.VisualStudio.Shell.VsMenus.guidStandardCommandSet2K) {
|
|
switch ((VsCommands2K)cmd) {
|
|
case VsCommands2K.RUNCUSTOMTOOL:
|
|
result |= QueryStatusResult.NOTSUPPORTED | QueryStatusResult.INVISIBLE;
|
|
return VSConstants.S_OK;
|
|
case VsCommands2K.EXCLUDEFROMPROJECT:
|
|
if (ItemNode.IsExcluded) {
|
|
result |= QueryStatusResult.NOTSUPPORTED | QueryStatusResult.INVISIBLE;
|
|
return VSConstants.S_OK;
|
|
}
|
|
break;
|
|
case VsCommands2K.INCLUDEINPROJECT:
|
|
if (ItemNode.IsExcluded) {
|
|
result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
|
|
return VSConstants.S_OK;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return base.QueryStatusOnNode(guidCmdGroup, cmd, pCmdText, ref result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Common File Node can only be deleted from file system.
|
|
/// </summary>
|
|
public override bool CanDeleteItem(__VSDELETEITEMOPERATION deleteOperation) {
|
|
if (IsLinkFile) {
|
|
// we don't delete link items, we only remove them from the project. If we were
|
|
// to return true when queried for both delete from storage and remove from project
|
|
// the user would be prompted about which they would like to do.
|
|
return deleteOperation == __VSDELETEITEMOPERATION.DELITEMOP_RemoveFromProject;
|
|
}
|
|
return deleteOperation == __VSDELETEITEMOPERATION.DELITEMOP_DeleteFromStorage;
|
|
}
|
|
#endregion
|
|
|
|
#region methods
|
|
|
|
public OleServiceProvider.ServiceCreatorCallback ServiceCreator {
|
|
get { return new OleServiceProvider.ServiceCreatorCallback(this.CreateServices); }
|
|
}
|
|
|
|
protected virtual object CreateServices(Type serviceType) {
|
|
object service = null;
|
|
if (typeof(EnvDTE.ProjectItem) == serviceType) {
|
|
service = GetAutomationObject();
|
|
}
|
|
return service;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|