Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1084)

Side by Side Diff: obsolete/Microsoft.VisualStudio.Project/ProjectContainerNode.cs

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /// Copyright (c) Microsoft Corporation. All rights reserved.
2
3 using System;
4 using System.Collections.Generic;
5 using System.Diagnostics;
6 using System.Diagnostics.CodeAnalysis;
7 using System.Globalization;
8 using System.IO;
9 using System.Runtime.InteropServices;
10 using Microsoft.VisualStudio.Project.Automation;
11 using Microsoft.VisualStudio.Shell;
12 using Microsoft.VisualStudio.Shell.Interop;
13 using MSBuild = Microsoft.Build.BuildEngine;
14
15 namespace Microsoft.VisualStudio.Project
16 {
17 [CLSCompliant(false), ComVisible(true)]
18 public abstract class ProjectContainerNode : ProjectNode,
19 IVsParentProject,
20 IBuildDependencyOnProjectContainer
21 {
22 #region fields
23
24 /// <summary>
25 /// Setting this flag to true will build all nested project when building this project
26 /// </summary>
27 private bool buildNestedProjectsOnBuild = true;
28
29 private ProjectElement nestedProjectElement;
30
31 /// <summary>
32 /// Defines the listener that would listen on file changes on th e nested project node.
33 /// </summary>
34 ///<devremark>
35 ///This might need a refactoring when nested projects can be add ed and removed by demand.
36 /// </devremark>
37 private FileChangeManager nestedProjectNodeReloader;
38 #endregion
39
40 #region ctors
41 protected ProjectContainerNode()
42 {
43 }
44 #endregion
45
46 #region properties
47 /// <summary>
48 /// Returns teh object that handles listening to file changes on the nested project files.
49 /// </summary>
50 internal FileChangeManager NestedProjectNodeReloader
51 {
52 get
53 {
54 if(this.nestedProjectNodeReloader == null)
55 {
56 this.nestedProjectNodeReloader = new Fil eChangeManager(this.Site);
57 this.nestedProjectNodeReloader.FileChang edOnDisk += this.OnNestedProjectFileChangedOnDisk;
58 }
59
60 return this.nestedProjectNodeReloader;
61 }
62 }
63 #endregion
64
65 #region overridden properties
66 /// <summary>
67 /// This is the object that will be returned by EnvDTE.Project.O bject for this project
68 /// </summary>
69 internal override object Object
70 {
71 get { return new OASolutionFolder<ProjectContainerNode>( this); }
72 }
73
74 #endregion
75
76 #region public overridden methods
77 /// <summary>
78 /// Gets the nested hierarchy.
79 /// </summary>
80 /// <param name="itemId">The item id.</param>
81 /// <param name="iidHierarchyNested">Identifier of the interface to be returned in ppHierarchyNested.</param>
82 /// <param name="ppHierarchyNested">Pointer to the interface who se identifier was passed in iidHierarchyNested.</param>
83 /// <param name="pItemId">Pointer to an item identifier of the r oot node of the nested hierarchy.</param>
84 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code. If ITEMID is not a nested hierarchy, this method re turns E_FAIL.</returns>
85 [CLSCompliant(false)]
86 public override int GetNestedHierarchy(UInt32 itemId, ref Guid i idHierarchyNested, out IntPtr ppHierarchyNested, out uint pItemId)
87 {
88 pItemId = VSConstants.VSITEMID_ROOT;
89 ppHierarchyNested = IntPtr.Zero;
90 if(this.FirstChild != null)
91 {
92 for(HierarchyNode n = this.FirstChild; n != null ; n = n.NextSibling)
93 {
94 NestedProjectNode p = n as NestedProject Node;
95
96 if(p != null && p.ID == itemId)
97 {
98 if(p.NestedHierarchy != null)
99 {
100 IntPtr iunknownPtr = Int Ptr.Zero;
101 int returnValue = VSCons tants.S_OK;
102 try
103 {
104 iunknownPtr = Ma rshal.GetIUnknownForObject(p.NestedHierarchy);
105 Marshal.QueryInt erface(iunknownPtr, ref iidHierarchyNested, out ppHierarchyNested);
106 }
107 catch(COMException e)
108 {
109 returnValue = e. ErrorCode;
110 }
111 finally
112 {
113 if(iunknownPtr ! = IntPtr.Zero)
114 {
115 Marshal. Release(iunknownPtr);
116 }
117 }
118
119 return returnValue;
120 }
121 break;
122 }
123 }
124 }
125
126 return VSConstants.E_FAIL;
127 }
128
129 public override int IsItemDirty(uint itemId, IntPtr punkDocData, out int pfDirty)
130 {
131 HierarchyNode hierNode = this.NodeFromItemId(itemId);
132 Debug.Assert(hierNode != null, "Hierarchy node not found ");
133 if(hierNode != this)
134 {
135 return ErrorHandler.ThrowOnFailure(hierNode.IsIt emDirty(itemId, punkDocData, out pfDirty));
136 }
137 else
138 {
139 return ErrorHandler.ThrowOnFailure(base.IsItemDi rty(itemId, punkDocData, out pfDirty));
140 }
141 }
142
143 public override int SaveItem(VSSAVEFLAGS dwSave, string silentSa veAsName, uint itemid, IntPtr punkDocData, out int pfCancelled)
144 {
145 HierarchyNode hierNode = this.NodeFromItemId(itemid);
146 Debug.Assert(hierNode != null, "Hierarchy node not found ");
147 if(hierNode != this)
148 {
149 return ErrorHandler.ThrowOnFailure(hierNode.Save Item(dwSave, silentSaveAsName, itemid, punkDocData, out pfCancelled));
150 }
151 else
152 {
153 return ErrorHandler.ThrowOnFailure(base.SaveItem (dwSave, silentSaveAsName, itemid, punkDocData, out pfCancelled));
154 }
155 }
156
157 protected override bool FilterItemTypeToBeAddedToHierarchy(strin g itemType)
158 {
159 if(String.Compare(itemType, ProjectFileConstants.SubProj ect, StringComparison.OrdinalIgnoreCase) == 0)
160 {
161 return true;
162 }
163 return base.FilterItemTypeToBeAddedToHierarchy(itemType) ;
164 }
165
166 /// <summary>
167 /// Called to reload a project item.
168 /// Reloads a project and its nested project nodes.
169 /// </summary>
170 /// <param name="itemId">Specifies itemid from VSITEMID.</param>
171 /// <param name="reserved">Reserved.</param>
172 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code. </returns>
173 public override int ReloadItem(uint itemId, uint reserved)
174 {
175 #region precondition
176 if(this.IsClosed)
177 {
178 return VSConstants.E_FAIL;
179 }
180 #endregion
181
182 NestedProjectNode node = this.NodeFromItemId(itemId) as NestedProjectNode;
183
184 if(node != null)
185 {
186 object propertyAsObject = node.GetProperty((int) __VSHPROPID.VSHPROPID_HandlesOwnReload);
187
188 if(propertyAsObject != null && (bool)propertyAsO bject)
189 {
190 node.ReloadItem(reserved);
191 }
192 else
193 {
194 this.ReloadNestedProjectNode(node);
195 }
196
197 return VSConstants.S_OK;
198 }
199
200 return base.ReloadItem(itemId, reserved);
201 }
202
203 /// <summary>
204 /// Reloads a project and its nested project nodes.
205 /// </summary>
206 protected override void Reload()
207 {
208 base.Reload();
209 this.CreateNestedProjectNodes();
210 }
211 #endregion
212
213 #region IVsParentProject
214 public virtual int OpenChildren()
215 {
216 IVsSolution solution = this.GetService(typeof(IVsSolutio n)) as IVsSolution;
217
218 Debug.Assert(solution != null, "Could not retrieve the s olution from the services provided by this project");
219 if(solution == null)
220 {
221 return VSConstants.E_FAIL;
222 }
223
224 IntPtr iUnKnownForSolution = IntPtr.Zero;
225 int returnValue = VSConstants.S_OK; // be optimistic.
226
227 try
228 {
229 this.DisableQueryEdit = true;
230 this.EventTriggeringFlag = ProjectNode.EventTrig gering.DoNotTriggerHierarchyEvents | ProjectNode.EventTriggering.DoNotTriggerTra ckerEvents;
231 iUnKnownForSolution = Marshal.GetIUnknownForObje ct(solution);
232
233 // notify SolutionEvents listeners that we are a bout to add children
234 IVsFireSolutionEvents fireSolutionEvents = Marsh al.GetTypedObjectForIUnknown(iUnKnownForSolution, typeof(IVsFireSolutionEvents)) as IVsFireSolutionEvents;
235 ErrorHandler.ThrowOnFailure(fireSolutionEvents.F ireOnBeforeOpeningChildren(this));
236
237 this.AddVirtualProjects();
238
239 ErrorHandler.ThrowOnFailure(fireSolutionEvents.F ireOnAfterOpeningChildren(this));
240 }
241 catch(Exception e)
242 {
243 // Exceptions are digested by the caller but we want then to be shown if not a ComException and if not in automation.
244 if(!(e is COMException) && !Utilities.IsInAutoma tionFunction(this.Site))
245 {
246 string title = null;
247 OLEMSGICON icon = OLEMSGICON.OLEMSGICON_ CRITICAL;
248 OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEM SGBUTTON_OK;
249 OLEMSGDEFBUTTON defaultButton = OLEMSGDE FBUTTON.OLEMSGDEFBUTTON_FIRST;
250 VsShellUtilities.ShowMessageBox(this.Sit e, title, e.Message, icon, buttons, defaultButton);
251 }
252
253 Trace.WriteLine("Exception : " + e.Message);
254 throw;
255 }
256 finally
257 {
258 this.DisableQueryEdit = false;
259
260 if(iUnKnownForSolution != IntPtr.Zero)
261 {
262 Marshal.Release(iUnKnownForSolution);
263 }
264
265 this.EventTriggeringFlag = ProjectNode.EventTrig gering.TriggerAll;
266 }
267
268 return returnValue;
269 }
270
271 public virtual int CloseChildren()
272 {
273 int returnValue = VSConstants.S_OK; // be optimistic.
274
275 IVsSolution solution = this.GetService(typeof(IVsSolutio n)) as IVsSolution;
276 Debug.Assert(solution != null, "Could not retrieve the s olution from the services provided by this project");
277
278 if(solution == null)
279 {
280 return VSConstants.E_FAIL;
281 }
282
283 IntPtr iUnKnownForSolution = IntPtr.Zero;
284
285 try
286 {
287 iUnKnownForSolution = Marshal.GetIUnknownForObje ct(solution);
288
289 // notify SolutionEvents listeners that we are a bout to close children
290 IVsFireSolutionEvents fireSolutionEvents = Marsh al.GetTypedObjectForIUnknown(iUnKnownForSolution, typeof(IVsFireSolutionEvents)) as IVsFireSolutionEvents;
291 ErrorHandler.ThrowOnFailure(fireSolutionEvents.F ireOnBeforeClosingChildren(this));
292
293 // If the removal crashes we never fire the clos e children event. IS that a problem?
294 this.RemoveNestedProjectNodes();
295
296 ErrorHandler.ThrowOnFailure(fireSolutionEvents.F ireOnAfterClosingChildren(this));
297 }
298 finally
299 {
300 if(iUnKnownForSolution != IntPtr.Zero)
301 {
302 Marshal.Release(iUnKnownForSolution);
303 }
304 }
305
306 return returnValue;
307 }
308 #endregion
309
310 #region IBuildDependencyOnProjectContainerNode
311 /// <summary>
312 /// Defines whether nested projects should be build with the par ent project
313 /// </summary>
314 public virtual bool BuildNestedProjectsOnBuild
315 {
316 get { return this.buildNestedProjectsOnBuild; }
317 set { this.buildNestedProjectsOnBuild = value; }
318 }
319
320 /// <summary>
321 /// Enumerates the nested hierachies that should be added to the build dependency list.
322 /// </summary>
323 /// <returns></returns>
324 public virtual IVsHierarchy[] EnumNestedHierachiesForBuildDepend ency()
325 {
326 List<IVsHierarchy> nestedProjectList = new List<IVsHiera rchy>();
327 // Add all nested project among projectContainer child n odes
328 for(HierarchyNode child = this.FirstChild; child != null ; child = child.NextSibling)
329 {
330 NestedProjectNode nestedProjectNode = child as N estedProjectNode;
331 if(nestedProjectNode != null)
332 {
333 nestedProjectList.Add(nestedProjectNode. NestedHierarchy);
334 }
335 }
336
337 return nestedProjectList.ToArray();
338 }
339 #endregion
340
341 #region helper methods
342
343 internal protected void RemoveNestedProjectNodes()
344 {
345 for(HierarchyNode n = this.FirstChild; n != null; n = n. NextSibling)
346 {
347 NestedProjectNode p = n as NestedProjectNode;
348 if(p != null)
349 {
350 p.CloseNestedProjectNode();
351 }
352 }
353
354 // We do not care of file changes after this.
355 this.NestedProjectNodeReloader.FileChangedOnDisk -= this .OnNestedProjectFileChangedOnDisk;
356 this.NestedProjectNodeReloader.Dispose();
357 }
358
359 /// <summary>
360 /// This is used when loading the project to loop through all th e items
361 /// and for each SubProject it finds, it create the project and a node
362 /// in our Hierarchy to hold the project.
363 /// </summary>
364 internal protected void CreateNestedProjectNodes()
365 {
366 // 1. Create a ProjectElement with the found item and th en Instantiate a new Nested project with this ProjectElement.
367 // 2. Link into the hierarchy.
368 // Read subprojects from from msbuildmodel
369 __VSCREATEPROJFLAGS creationFlags = __VSCREATEPROJFLAGS. CPF_NOTINSLNEXPLR | __VSCREATEPROJFLAGS.CPF_SILENT;
370
371 if(this.IsNewProject)
372 {
373 creationFlags |= __VSCREATEPROJFLAGS.CPF_CLONEFI LE;
374 }
375 else
376 {
377 creationFlags |= __VSCREATEPROJFLAGS.CPF_OPENFIL E;
378 }
379
380 foreach(MSBuild.BuildItem item in this.BuildProject.Eval uatedItems)
381 {
382 if(String.Compare(item.Name, ProjectFileConstant s.SubProject, StringComparison.OrdinalIgnoreCase) == 0)
383 {
384 this.nestedProjectElement = new ProjectE lement(this, item, false);
385
386 if(!this.IsNewProject)
387 {
388 AddExistingNestedProject(null, c reationFlags);
389 }
390 else
391 {
392 // If we are creating the subpro ject from a vstemplate/vsz file
393 bool isVsTemplate = Utilities.Is TemplateFile(GetProjectTemplatePath(null));
394 if(isVsTemplate)
395 {
396 RunVsTemplateWizard(null , true);
397 }
398 else
399 {
400 // We are cloning the sp ecified project file
401 AddNestedProjectFromTemp late(null, creationFlags);
402 }
403 }
404 }
405 }
406
407 this.nestedProjectElement = null;
408 }
409 /// <summary>
410 /// Add an existing project as a nested node of our hierarchy.
411 /// This is used while loading the project and can also be used
412 /// to add an existing project to our hierarchy.
413 /// </summary>
414 protected internal virtual NestedProjectNode AddExistingNestedPr oject(ProjectElement element, __VSCREATEPROJFLAGS creationFlags)
415 {
416 ProjectElement elementToUse = (element == null) ? this.n estedProjectElement : element;
417
418 if(elementToUse == null)
419 {
420 throw new ArgumentNullException("element");
421 }
422
423 string filename = elementToUse.GetFullPathForElement();
424 // Delegate to AddNestedProjectFromTemplate. Because we pass flags that specify open project rather then clone, this will works.
425 Debug.Assert((creationFlags & __VSCREATEPROJFLAGS.CPF_OP ENFILE) == __VSCREATEPROJFLAGS.CPF_OPENFILE, "__VSCREATEPROJFLAGS.CPF_OPENFILE s hould have been specified, did you mean to call AddNestedProjectFromTemplate?");
426 return AddNestedProjectFromTemplate(filename, Path.GetDi rectoryName(filename), Path.GetFileName(filename), elementToUse, creationFlags);
427 }
428
429 /// <summary>
430 /// Let the wizard code execute and provide us the information w e need.
431 /// Our SolutionFolder automation object should be called back w ith the
432 /// details at which point it will call back one of our method t o add
433 /// a nested project.
434 /// If you are trying to add a new subproject this is probably t he
435 /// method you want to call. If you are just trying to clone a t emplate
436 /// project file, then AddNestedProjectFromTemplate is what you want.
437 /// </summary>
438 /// <param name="element">The project item to use as the base of the nested project.</param>
439 /// <param name="silent">true if the wizard should run silently, otherwise false.</param>
440 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBe CasedCorrectly", MessageId = "Vs")]
441 protected internal void RunVsTemplateWizard(ProjectElement eleme nt, bool silent)
442 {
443 ProjectElement elementToUse = (element == null) ? this.n estedProjectElement : element;
444
445 if(elementToUse == null)
446 {
447 throw new ArgumentNullException("element");
448 }
449 this.nestedProjectElement = elementToUse;
450
451 Automation.OAProject oaProject = GetAutomationObject() a s Automation.OAProject;
452 if(oaProject == null || oaProject.ProjectItems == null)
453 throw new System.InvalidOperationException(SR.Ge tString(SR.InvalidAutomationObject, CultureInfo.CurrentUICulture));
454 Debug.Assert(oaProject.Object != null, "The project auto mation object should have set the Object to the SolutionFolder");
455 Automation.OASolutionFolder<ProjectContainerNode> folder = oaProject.Object as Automation.OASolutionFolder<ProjectContainerNode>;
456
457 // Prepare the parameters to pass to RunWizardFile
458 string destination = elementToUse.GetFullPathForElement( );
459 string template = this.GetProjectTemplatePath(elementToU se);
460
461 object[] wizParams = new object[7];
462 wizParams[0] = EnvDTE.Constants.vsWizardAddSubProject;
463 wizParams[1] = Path.GetFileNameWithoutExtension(destinat ion);
464 wizParams[2] = oaProject.ProjectItems;
465 wizParams[3] = Path.GetDirectoryName(destination);
466 wizParams[4] = Path.GetFileNameWithoutExtension(destinat ion);
467 wizParams[5] = Path.GetDirectoryName(folder.DTE.FullName ); //VS install dir
468 wizParams[6] = silent;
469
470 IVsDetermineWizardTrust wizardTrust = this.GetService(ty peof(SVsDetermineWizardTrust)) as IVsDetermineWizardTrust;
471 if(wizardTrust != null)
472 {
473 Guid guidProjectAdding = Guid.Empty;
474
475 // In case of a project template an empty guid s hould be added as the guid parameter. See env\msenv\core\newtree.h IsTrustedTemp late method definition.
476 ErrorHandler.ThrowOnFailure(wizardTrust.OnWizard Initiated(template, ref guidProjectAdding));
477 }
478
479 try
480 {
481 // Make the call to execute the wizard. This sho uld cause AddNestedProjectFromTemplate to be
482 // called back with the correct set of parameter s.
483 EnvDTE.IVsExtensibility extensibilityService = ( EnvDTE.IVsExtensibility)GetService(typeof(EnvDTE.IVsExtensibility));
484 EnvDTE.wizardResult result = extensibilityServic e.RunWizardFile(template, 0, ref wizParams);
485 if(result == EnvDTE.wizardResult.wizardResultFai lure)
486 throw new COMException();
487 }
488 finally
489 {
490 if(wizardTrust != null)
491 {
492 ErrorHandler.ThrowOnFailure(wizardTrust. OnWizardCompleted());
493 }
494 }
495 }
496
497 /// <summary>
498 /// This will clone a template project file and add it as a
499 /// subproject to our hierarchy.
500 /// If you want to create a project for which there exist a
501 /// vstemplate, consider using RunVsTemplateWizard instead.
502 /// </summary>
503 protected internal virtual NestedProjectNode AddNestedProjectFro mTemplate(ProjectElement element, __VSCREATEPROJFLAGS creationFlags)
504 {
505 ProjectElement elementToUse = (element == null) ? this.n estedProjectElement : element;
506
507 if(elementToUse == null)
508 {
509 throw new ArgumentNullException("element");
510 }
511 string destination = elementToUse.GetFullPathForElement( );
512 string template = this.GetProjectTemplatePath(elementToU se);
513
514 return this.AddNestedProjectFromTemplate(template, Path. GetDirectoryName(destination), Path.GetFileName(destination), elementToUse, crea tionFlags);
515 }
516
517 /// <summary>
518 /// This can be called directly or through RunVsTemplateWizard.
519 /// This will clone a template project file and add it as a
520 /// subproject to our hierarchy.
521 /// If you want to create a project for which there exist a
522 /// vstemplate, consider using RunVsTemplateWizard instead.
523 /// </summary>
524 protected internal virtual NestedProjectNode AddNestedProjectFro mTemplate(string fileName, string destination, string projectName, ProjectElemen t element, __VSCREATEPROJFLAGS creationFlags)
525 {
526 // If this is project creation and the template specifie d a subproject in its project file, this.nestedProjectElement will be used
527 ProjectElement elementToUse = (element == null) ? this.n estedProjectElement : element;
528
529 if(elementToUse == null)
530 {
531 // If this is null, this means MSBuild does not know anything about our subproject so add an MSBuild item for it
532 elementToUse = new ProjectElement(this, fileName , ProjectFileConstants.SubProject);
533 }
534
535 NestedProjectNode node = CreateNestedProjectNode(element ToUse);
536 node.Init(fileName, destination, projectName, creationFl ags);
537
538 // In case that with did not have an existing element, o r the nestedProjectelement was null
539 // and since Init computes the final path, set the MSBu ild item to that path
540 if(this.nestedProjectElement == null)
541 {
542 string relativePath = node.Url;
543 if(Path.IsPathRooted(relativePath))
544 {
545 relativePath = this.ProjectFolder;
546 if(!relativePath.EndsWith("/\\", StringC omparison.Ordinal))
547 {
548 relativePath += Path.DirectorySe paratorChar;
549 }
550
551 relativePath = new Url(relativePath).Mak eRelative(new Url(node.Url));
552 }
553
554 elementToUse.Rename(relativePath);
555 }
556
557 this.AddChild(node);
558 return node;
559 }
560
561 /// <summary>
562 /// Override this method if you want to provide your own type of nodes.
563 /// This would be the case if you derive a class from NestedProj ectNode
564 /// </summary>
565 protected virtual NestedProjectNode CreateNestedProjectNode(Proj ectElement element)
566 {
567 return new NestedProjectNode(this, element);
568 }
569
570 /// <summary>
571 /// Links the nested project nodes to the solution. The default implementation parses all nested project nodes and calles AddVirtualProjectEx on them.
572 /// </summary>
573 protected virtual void AddVirtualProjects()
574 {
575 for(HierarchyNode child = this.FirstChild; child != null ; child = child.NextSibling)
576 {
577 NestedProjectNode nestedProjectNode = child as N estedProjectNode;
578 if(nestedProjectNode != null)
579 {
580 nestedProjectNode.AddVirtualProject();
581 }
582 }
583 }
584
585 /// <summary>
586 /// Based on the Template and TypeGuid properties of the
587 /// element, generate the full template path.
588 ///
589 /// TypeGuid should be the Guid of a registered project factory.
590 /// Template can be a full path, a project template (for project s
591 /// that support VsTemplates) or a relative path (for other proj ects).
592 /// </summary>
593 protected virtual string GetProjectTemplatePath(ProjectElement e lement)
594 {
595 ProjectElement elementToUse = (element == null) ? this.n estedProjectElement : element;
596
597 if(elementToUse == null)
598 {
599 throw new ArgumentNullException("element");
600 }
601
602 string templateFile = elementToUse.GetMetadata(ProjectFi leConstants.Template);
603 Debug.Assert(!String.IsNullOrEmpty(templateFile), "No te mplate file has been specified in the template attribute in the project file");
604
605 string fullPath = templateFile;
606 if(!Path.IsPathRooted(templateFile))
607 {
608 RegisteredProjectType registeredProjectType = th is.GetRegisteredProject(elementToUse);
609
610 // This is not a full path
611 Debug.Assert(registeredProjectType != null && (! String.IsNullOrEmpty(registeredProjectType.DefaultProjectExtensionValue) || !Str ing.IsNullOrEmpty(registeredProjectType.WizardTemplatesDirValue)), " Registered wizard directory value not set in the registry.");
612
613 // See if this specify a VsTemplate file
614 fullPath = registeredProjectType.GetVsTemplateFi le(templateFile);
615 if(String.IsNullOrEmpty(fullPath))
616 {
617 // Default to using the WizardTemplateDi r to calculate the absolute path
618 fullPath = Path.Combine(registeredProjec tType.WizardTemplatesDirValue, templateFile);
619 }
620 }
621
622 return fullPath;
623 }
624
625 /// <summary>
626 /// Get information from the registry based for the project
627 /// factory corresponding to the TypeGuid of the element
628 /// </summary>
629 private RegisteredProjectType GetRegisteredProject(ProjectElemen t element)
630 {
631 ProjectElement elementToUse = (element == null) ? this.n estedProjectElement : element;
632
633 if(elementToUse == null)
634 {
635 throw new ArgumentNullException("element");
636 }
637
638 // Get the project type guid from project elementToUse
639 string typeGuidString = elementToUse.GetMetadataAndThrow (ProjectFileConstants.TypeGuid, new Exception());
640 Guid projectFactoryGuid = new Guid(typeGuidString);
641
642 EnvDTE.DTE dte = this.ProjectMgr.Site.GetService(typeof( EnvDTE.DTE)) as EnvDTE.DTE;
643 Debug.Assert(dte != null, "Could not get the automation object from the services exposed by this project");
644
645 if(dte == null)
646 throw new InvalidOperationException();
647
648 RegisteredProjectType registeredProjectType = Registered ProjectType.CreateRegisteredProjectType(projectFactoryGuid);
649 Debug.Assert(registeredProjectType != null, "Could not r ead the registry setting associated to this project.");
650 if(registeredProjectType == null)
651 {
652 throw new InvalidOperationException();
653 }
654 return registeredProjectType;
655 }
656
657 /// <summary>
658 /// Reloads a nested project node by deleting it and readding it .
659 /// </summary>
660 /// <param name="node">The node to reload.</param>
661 protected virtual void ReloadNestedProjectNode(NestedProjectNode node)
662 {
663 if(node == null)
664 {
665 throw new ArgumentNullException("node");
666 }
667
668 IVsSolution solution = this.GetService(typeof(IVsSolutio n)) as IVsSolution;
669
670 if(solution == null)
671 {
672 throw new InvalidOperationException();
673 }
674
675 NestedProjectNode newNode = null;
676 try
677 {
678 // (VS 2005 UPDATE) When deleting and re-adding the nested project,
679 // we do not want SCC to see this as a delete an d add operation.
680 this.EventTriggeringFlag = ProjectNode.EventTrig gering.DoNotTriggerTrackerEvents;
681
682 // notify SolutionEvents listeners that we are a bout to add children
683 IVsFireSolutionEvents fireSolutionEvents = solut ion as IVsFireSolutionEvents;
684
685 if(fireSolutionEvents == null)
686 {
687 throw new InvalidOperationException();
688 }
689
690 ErrorHandler.ThrowOnFailure(fireSolutionEvents.F ireOnBeforeUnloadProject(node.NestedHierarchy));
691
692 int isDirtyAsInt = 0;
693 this.IsDirty(out isDirtyAsInt);
694
695 bool isDirty = (isDirtyAsInt == 0) ? false : tru e;
696
697 ProjectElement element = node.ItemNode;
698 node.CloseNestedProjectNode();
699
700 // Remove from the solution
701 this.RemoveChild(node);
702
703 // Now readd it
704 try
705 {
706 __VSCREATEPROJFLAGS flags = __VSCREATEPR OJFLAGS.CPF_NOTINSLNEXPLR | __VSCREATEPROJFLAGS.CPF_SILENT | __VSCREATEPROJFLAGS .CPF_OPENFILE;
707 newNode = this.AddExistingNestedProject( element, flags);
708 newNode.AddVirtualProject();
709 }
710 catch(Exception e)
711 {
712 // We get a System.Exception if anything failed, thus we have no choice but catch it.
713 // Exceptions are digested by VS. Show t he error if not in automation.
714 if(!Utilities.IsInAutomationFunction(thi s.Site))
715 {
716 string message = (String.IsNullO rEmpty(e.Message)) ? SR.GetString(SR.NestedProjectFailedToReload, CultureInfo.Cu rrentUICulture) : e.Message;
717 string title = string.Empty;
718 OLEMSGICON icon = OLEMSGICON.OLE MSGICON_CRITICAL;
719 OLEMSGBUTTON buttons = OLEMSGBUT TON.OLEMSGBUTTON_OK;
720 OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
721 VsShellUtilities.ShowMessageBox( this.Site, title, message, icon, buttons, defaultButton);
722 }
723
724 // Do not digest exception. let the call er handle it. If in a later stage this exception is not digested then the above messagebox is not needed.
725 throw;
726 }
727
728 #if DEBUG
729 IVsHierarchy nestedHierarchy;
730 ErrorHandler.ThrowOnFailure(solution.GetProjectO fUniqueName(newNode.GetMkDocument(), out nestedHierarchy));
731 Debug.Assert(nestedHierarchy != null && Utilitie s.IsSameComObject(nestedHierarchy, newNode.NestedHierarchy), "The nested hierrac hy was not reloaded correctly.");
732 #endif
733 this.SetProjectFileDirty(isDirty);
734
735 ErrorHandler.ThrowOnFailure(fireSolutionEvents.F ireOnAfterLoadProject(newNode.NestedHierarchy));
736 }
737 finally
738 {
739 // In this scenario the nested project failed to unload or reload the nested project. We will unload the whole project, otherwis e the nested project is lost.
740 // This is similar to the scenario when one want s to open a project and the nested project cannot be loaded because for example the project file has xml errors.
741 // We should note that we rely here that if the unload fails then exceptions are not digested and are shown to the user.
742 if(newNode == null || newNode.NestedHierarchy == null)
743 {
744 ErrorHandler.ThrowOnFailure(solution.Clo seSolutionElement((uint)__VSSLNCLOSEOPTIONS.SLNCLOSEOPT_UnloadProject | (uint)__ VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, this, 0));
745 }
746 else
747 {
748 this.EventTriggeringFlag = ProjectNode.E ventTriggering.TriggerAll;
749 }
750 }
751 }
752
753 /// <summary>
754 /// Event callback. Called when one of the nested project files is changed.
755 /// </summary>
756 /// <param name="sender">The FileChangeManager object.</param>
757 /// <param name="e">Event args containing the file name that was updated.</param>
758 private void OnNestedProjectFileChangedOnDisk(object sender, Fil eChangedOnDiskEventArgs e)
759 {
760 #region Pre-condition validation
761 Debug.Assert(e != null, "No event args specified for the FileChangedOnDisk event");
762
763 // We care only about time change for reload.
764 if((e.FileChangeFlag & _VSFILECHANGEFLAGS.VSFILECHG_Time ) == 0)
765 {
766 return;
767 }
768
769 // test if we actually have a document for this id.
770 string moniker;
771 this.GetMkDocument(e.ItemID, out moniker);
772 Debug.Assert(NativeMethods.IsSamePath(moniker, e.FileNam e), " The file + " + e.FileName + " has changed but we could not retrieve the pa th for the item id associated to the path.");
773 #endregion
774
775 bool reload = true;
776 if(!Utilities.IsInAutomationFunction(this.Site))
777 {
778 // Prompt to reload the nested project file. We use the moniker here since the filename from the event arg is canonicalized.
779 string message = String.Format(CultureInfo.Curre ntCulture, SR.GetString(SR.QueryReloadNestedProject, CultureInfo.CurrentUICultur e), moniker);
780 string title = string.Empty;
781 OLEMSGICON icon = OLEMSGICON.OLEMSGICON_INFO;
782 OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON _YESNO;
783 OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON. OLEMSGDEFBUTTON_FIRST;
784 reload = (VsShellUtilities.ShowMessageBox(this.S ite, message, title, icon, buttons, defaultButton) == NativeMethods.IDYES);
785 }
786
787 if(reload)
788 {
789 // We have to use here the interface method call , since it might be that specialized project nodes like the project container it em
790 // is owerwriting the default functionality.
791 this.ReloadItem(e.ItemID, 0);
792 }
793 }
794 #endregion
795 }
796 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698