Exemple #1
0
        /// <summary>
        /// Notifies all of the listeners that a project has begun building.
        /// </summary>
        /// <returns>true if the build should continue; false if one or more of the listeners requested
        /// that the build should be canceled.</returns>
        public bool OnBuildBegin()
        {
            bool continueBuilding = true;

            // Let all of our listeners know that the build has started.
            Tracer.WriteLineInformation(classType, "OnBuildBegin", "Notifying all of our listeners that the build has started.");

            // There are some cases where the collection is changed while we're iterating it.
            // To be safe, we'll create a copy of the collection and iterate over that.
            // We just want a shallow copy, though, and not a deep (Clone) copy.
            ArrayList clone = new ArrayList(this.Values);

            foreach (IVsBuildStatusCallback eventItem in clone)
            {
                try
                {
                    int continueFlag = Convert.ToInt32(continueBuilding);
                    eventItem.BuildBegin(ref continueFlag);
                    if (continueFlag == 0)
                    {
                        continueBuilding = false;
                    }
                }
                catch (Exception e)
                {
                    Tracer.WriteLine(classType, "OnBuildBegin", Tracer.Level.Warning, "There was an exception in one of the listener's event handling code: {0}", e.ToString());
                }
            }

            return(continueBuilding);
        }
Exemple #2
0
        /// <summary>
        /// Generates a unique document name for a new node under the parent node.
        /// </summary>
        /// <param name="suggestedRoot">The suggested root to use for the unique name.</param>
        /// <param name="extension">The extension to use for the new file or folder (with or without the leading '.'). Can be null or empty.</param>
        /// <param name="isFolder">Indicates whether the new name is intended to be a file or a folder.</param>
        /// <returns>A unique document name for a new node under the this node.</returns>
        public string GenerateUniqueName(string suggestedRoot, string extension, bool isFolder)
        {
            Tracer.VerifyStringArgument(suggestedRoot, "suggestedRoot");

            int    suffixNumber = 0;
            bool   foundUnique  = false;
            string uniqueName   = String.Empty;

            // Canonicalize the extension by setting it either to "" or prepend it with a '.'
            extension = ((extension == null || extension.Length == 0) ? String.Empty : PackageUtility.EnsureLeadingChar(extension, '.'));

            // We have to make sure that this item doesn't already exist in the hierarchy and the file system.
            while (!foundUnique)
            {
                if (suffixNumber == 0)
                {
                    uniqueName = suggestedRoot + extension;
                }
                else
                {
                    uniqueName = suggestedRoot + suffixNumber + extension;
                }

                // Look in the hierarchy to see if there is an existing item with the proposed name.
                foundUnique = true;
                foreach (Node node in this.Children)
                {
                    if (PackageUtility.FileStringEquals(uniqueName, node.Caption))
                    {
                        foundUnique = false;
                        break;
                    }
                }

                // If the name is unique within the hierarchy, we still need to check the file system.
                if (foundUnique)
                {
                    string pathToCheck = Path.Combine(this.AbsoluteDirectory, uniqueName);
                    if (isFolder && Directory.Exists(pathToCheck))
                    {
                        foundUnique = false;
                    }
                    else if (!isFolder && File.Exists(pathToCheck))
                    {
                        foundUnique = false;
                    }
                    else
                    {
                        // Ok, we found a unique name.
                        break;
                    }
                }

                // Increment the number to append to the root part of the path.
                suffixNumber++;
            }

            Tracer.WriteLineInformation(classType, "GenerateUniqueName", "Found a unique name for a new node. New name = '{0}'.", uniqueName);
            return(uniqueName);
        }
Exemple #3
0
        /// <summary>
        /// Checks whether the proposed caption already exists, meaning that there is not an existing file
        /// or folder at the root path or that there is not already a sibling hierarchy item with the same name.
        /// </summary>
        /// <param name="newCaption">The proposed caption.</param>
        /// <param name="newPath">The proposed new absolute file path.</param>
        /// <remarks>The method throws an exception if the caption already exists.</remarks>
        private void VerifyCaptionDoesNotExist(string newCaption, string newPath)
        {
            bool valid = true;

            // Make sure there isn't already a sibling with the same caption. The root node has no siblings.
            if (this.Parent != null)
            {
                foreach (Node sibling in this.Parent.Children)
                {
                    bool thisIsSibling = Object.ReferenceEquals(sibling, this);
                    bool captionsEqual = (PackageUtility.FileStringEquals(newCaption, sibling.Caption));
                    // We can have a file system node that is the same name as a virtual node.
                    // For example, we can name a file/folder "Library References" if we want,
                    // even though that is already in the hierarchy.
                    bool isExactlyOneVirtual = ((this.IsVirtual && !sibling.IsVirtual) || (!this.IsVirtual && sibling.IsVirtual));
                    if (!thisIsSibling && captionsEqual && !isExactlyOneVirtual)
                    {
                        valid = false;
                        break;
                    }
                }
            }

            if (valid)
            {
                // Now check to see if the file system already contains a file/folder by the same name.
                valid = ((this.IsFile && !File.Exists(newPath)) || (this.IsFolder && !Directory.Exists(newPath)));
            }

            if (!valid)
            {
                Tracer.WriteLineInformation(classType, "VerifyCaption", "An existing file or folder named '{0}' already exists on the disk.", newCaption);
                throw new InvalidOperationException(SconceStrings.ErrorItemAlreadyExistsOnDisk(newCaption));
            }
        }
Exemple #4
0
        /// <summary>
        /// Notifies all of the listeners that a project has finished building.
        /// </summary>
        /// <param name="success">true if the build operation completed successfully. On an up-to-date check,
        /// <paramref name="success"/> must be set to true when the project configuration is up to date and
        /// false when the project configuration is not up to date.</param>
        public void OnBuildEnd(bool success)
        {
            // Let all of our listeners know that the build has ended.
            if (success)
            {
                Tracer.WriteLineInformation(classType, "OnBuildEnd", "Notifying all of our listeners that the build has ended successfully.");
            }
            else
            {
                Tracer.WriteLineInformation(classType, "OnBuildEnd", "Notifying all of our listeners that the build has ended with errors.");
            }

            int successFlag = Convert.ToInt32(success);

            // There are some cases where the collection is changed while we're iterating it.
            // To be safe, we'll create a copy of the collection and iterate over that.
            // We just want a shallow copy, though, and not a deep (Clone) copy.
            ArrayList clone = new ArrayList(this.Values);

            foreach (IVsBuildStatusCallback eventItem in clone)
            {
                try
                {
                    eventItem.BuildEnd(successFlag);
                }
                catch (Exception e)
                {
                    Tracer.WriteLine(classType, "OnBuildEnd", Tracer.Level.Warning, "There was an exception in one of the listener's event handling code: {0}", e.ToString());
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// Does the actual work of changing the caption after all of the verifications have been done
        /// that it's Ok to move the file.
        /// </summary>
        /// <param name="newCaption">The new caption.</param>
        /// <param name="newPath">The new absolute path.</param>
        public override void MoveNodeOnCaptionChange(string newCaption, string newPath)
        {
            string     oldPath   = this.AbsolutePath;
            IVsUIShell vsUIShell = (IVsUIShell)this.Hierarchy.ServiceProvider.GetServiceOrThrow(typeof(SVsUIShell), typeof(IVsUIShell), classType, "MoveNodeOnCaptionChange");

            // Tell the environment to stop listening to file change events on the old file.
            using (FileChangeNotificationSuspender notificationSuspender = new FileChangeNotificationSuspender(oldPath))
            {
                // Make sure the environment says we can start the rename.
                if (!this.Hierarchy.AttachedProject.Tracker.CanRenameProject(oldPath, newPath))
                {
                    // If the user chose to not check out the solution file, then we want to throw the
                    // save cancelled HRESULT.
                    throw new COMException("User cancelled the solution file check out.", NativeMethods.OLE_E_PROMPTSAVECANCELLED);
                }

                // Move the file on the file system to match the new name.
                if (File.Exists(oldPath) && !File.Exists(newPath))
                {
                    Tracer.WriteLineInformation(classType, "MoveNodeOnCaptionChange", "Renaming the project file '{0}' to '{1}'.", oldPath, newPath);
                    File.Move(oldPath, newPath);
                }

                // Tell the environment that we're done renaming the document.
                this.Hierarchy.AttachedProject.Tracker.OnProjectRenamed(oldPath, newPath);

                // Update the property browser.
                vsUIShell.RefreshPropertyBrowser(0);
            }
        }
Exemple #6
0
        /// <summary>
        /// Initializes this package.
        /// </summary>
        private void Initialize()
        {
            int hr = NativeMethods.S_OK;

            // If we have any services to proffer, let's do it now.
            if (this.services != null)
            {
                IProfferService ps = (IProfferService)this.GetService(typeof(IProfferService));
                Tracer.Assert(ps != null, "We have services to proffer, but can't get an instance of IProfferService.");
                if (ps != null)
                {
                    foreach (DictionaryEntry entry in this.services)
                    {
                        ProfferedService service = entry.Value as ProfferedService;
                        if (service != null)
                        {
                            Type serviceType = (Type)entry.Key;
                            Guid serviceGuid = serviceType.GUID;
                            uint cookie;
                            hr             = ps.ProfferService(ref serviceGuid, this, out cookie);
                            service.Cookie = cookie;
                            if (NativeMethods.Failed(hr))
                            {
                                string message = this.Context.NativeResources.GetString(ResId.IDS_E_FAILEDTOPROFFERSERVICE, serviceType.FullName);
                                Tracer.Fail(message);
                                throw new COMException(message, hr);
                            }
                        }
                    }
                }
            }

            // Create the Project Factory and register our project types.
            Tracer.WriteLineInformation(classType, "Initialize", "Creating the project factory and registering our project types.");
            IVsRegisterProjectTypes regProjTypes = (IVsRegisterProjectTypes)this.Context.ServiceProvider.GetServiceOrThrow(typeof(SVsRegisterProjectTypes), typeof(IVsRegisterProjectTypes), classType, "Initialize");

            this.projectFactory = this.CreateProjectFactory();
            Guid projectGuid = this.ProjectTypeGuid;

            hr = regProjTypes.RegisterProjectType(ref projectGuid, this.projectFactory, out this.projectCookie);
            if (NativeMethods.Succeeded(hr))
            {
                Tracer.WriteLine(classType, "Initialize", Tracer.Level.Information, "Successfully registered our project types.");
            }
            else
            {
                Tracer.Fail("Failed to register the Wix Project type. HRESULT = 0x{0}", hr.ToString("x"));
            }
        }
Exemple #7
0
        /// <summary>
        /// Called right after the value is removed from the collection.
        /// </summary>
        /// <param name="index">The index of the item removed from the collection.</param>
        /// <param name="value">The value just removed from the collection.</param>
        protected override void OnRemoveComplete(int index, object value)
        {
            Node node = (Node)value;

            // First remove the children of the node.
            FolderNode folderNode = node as FolderNode;

            if (folderNode != null)
            {
                folderNode.Children.Clear();
            }

            // Remove the node from our lookup tables.
            this.idTable.Remove(node.HierarchyId);
            this.pathTable.Remove(node.AbsolutePath);

            // Set the node's parent to null.
            node.Parent = null;

            // This is useful information to trace, so we'll use the Hierarchy category and the Information level,
            // which will allow this to be traced by default.
            Tracer.WriteLineInformation(classType, "OnRemoveComplete", "Removed '{0}' from the hierarchy.", node);
        }
        /// <summary>
        /// Makes sure that another build is not processing, resets the build flags, and lets
        /// the environment know that the build has started.
        /// </summary>
        /// <param name="outputPane">The <see cref="IVsOutputWindowPane"/> to use for writing messages to the environment.</param>
        /// <returns>true if the build should proceed; otherwise, false.</returns>
        protected virtual bool PrepareBuild(IVsOutputWindowPane outputPane)
        {
            // Check to make sure another build is not happening.
            if (this.IsBuilding)
            {
                string message = Package.Instance.Context.NativeResources.GetString(ResourceId.IDS_ANOTHERPROJECTBUILDING);
                Package.Instance.Context.ShowMessageBox(message, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_WARNING);
                Tracer.WriteLineInformation(classType, "PrepareBuild", "Another build is already running. Skipping this build.");
                return(false);
            }

            this.IsBuilding      = true;
            this.buildSuccessful = false;
            this.outputPane      = outputPane;

            // Let the environment know that we've started the build.
            this.cancelBuild = !this.eventListeners.OnBuildBegin();
            if (this.CancelBuild)
            {
                this.FinishBuild(false);
                return(false);
            }
            return(true);
        }
Exemple #9
0
        int IVsProjectFactory.CreateProject(string pszFilename, string pszLocation, string pszName, uint grfCreateFlags, ref Guid iidProject, out IntPtr ppvProject, out int pfCanceled)
        {
            IntPtr pUnk = IntPtr.Zero;

            pfCanceled = 0;
            ppvProject = IntPtr.Zero;

            bool loadedSuccessfully = false;

            try
            {
                Tracer.VerifyStringArgument(pszFilename, "pszFilename");

                __VSCREATEPROJFLAGS createFlags = (__VSCREATEPROJFLAGS)grfCreateFlags;

                // Get the right version of the project serializer.
                ProjectSerializer serializer = this.CreateSerializer(pszFilename);

                // Do we need to suppress any load failures from being reported to the end user.
                serializer.SilentFailures = ((createFlags & __VSCREATEPROJFLAGS.CPF_SILENT) == __VSCREATEPROJFLAGS.CPF_SILENT);

                // Now we need to load the project, either from a template file or from an existing file.
                bool openExisting     = ((createFlags & __VSCREATEPROJFLAGS.CPF_OPENFILE) == __VSCREATEPROJFLAGS.CPF_OPENFILE);
                bool openFromTemplate = ((createFlags & __VSCREATEPROJFLAGS.CPF_CLONEFILE) == __VSCREATEPROJFLAGS.CPF_CLONEFILE);
                Tracer.Assert((openExisting && !openFromTemplate) || (!openExisting && openFromTemplate), "The grfCreateFlags are incorrect. You can't have both opening existing and opening from template. Flags={0}", createFlags);

                if (openExisting)
                {
                    Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "Attempting to load project: File name={0} Location={1} Name={2} GUID={3}.", pszFilename, pszLocation, pszName, iidProject.ToString("B").ToUpper(CultureInfo.InvariantCulture));
                    loadedSuccessfully = serializer.Load(pszFilename);

                    if (loadedSuccessfully)
                    {
                        Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "Successfully loaded project '{0}'.", pszFilename);
                    }
                    else
                    {
                        Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "There were errors in loading project '{0}'.", pszFilename);
                    }
                }
                else
                {
                    Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "Attempting to create a new project from a template: File name={0} Location={1} Name={2} GUID={3}.", pszFilename, pszLocation, pszName, iidProject.ToString("B").ToUpper(CultureInfo.InvariantCulture));
                    Tracer.VerifyStringArgument(pszLocation, "pszLocation");
                    Tracer.VerifyStringArgument(pszName, "pszName");

                    string destinationFile = Path.Combine(pszLocation, pszName);
                    loadedSuccessfully = serializer.LoadFromTemplate(pszFilename, destinationFile);

                    if (loadedSuccessfully)
                    {
                        Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "Successfully loaded project '{0}'.", pszFilename);
                    }
                    else
                    {
                        Tracer.WriteLineInformation(classType, "IVsProjectFactory.CreateProject", "There were errors in loading project '{0}'.", pszFilename);
                    }
                }

                if (loadedSuccessfully)
                {
                    // Once we've loaded the project, we need to return the COM object that the environment is requesting.
                    pUnk = Marshal.GetIUnknownForObject(serializer.Project);
                    int hr = Marshal.QueryInterface(pUnk, ref iidProject, out ppvProject);
                    Tracer.Assert(NativeMethods.Succeeded(hr), "Cannot get the requested project interface ({0}): returned {1}", iidProject.ToString("B").ToUpper(CultureInfo.InvariantCulture), hr);
                    NativeMethods.ThrowOnFailure(hr);
                }
            }
            catch (Exception e)
            {
                Package.Instance.Context.NotifyInternalError(e.ToString());
            }
            finally
            {
                if (pUnk != IntPtr.Zero)
                {
                    Marshal.Release(pUnk);
                }
            }

            return(loadedSuccessfully ? NativeMethods.S_OK : NativeMethods.E_FAIL);
        }
Exemple #10
0
        /// <summary>
        /// Opens the standard editor for this file type in Visual Studio.
        /// </summary>
        /// <param name="logicalView">The type of view in which to open the document.</param>
        /// <param name="existingDocumentData">
        /// Passed through to the IVsUIShellOpenDocument.OpenStandardEditor or OpenSpecificEditor, which
        /// will then determine if the document is already opened and reused the open window.
        /// </param>
        /// <param name="physicalView">
        /// Name of the physical view if we're opening with a specific editor. Not used if opening with a standard editor.
        /// </param>
        /// <param name="specificEditor">The GUID of the specific registered editor to use to open this node.</param>
        /// <returns>The <see cref="IVsWindowFrame"/> object that contains the opened document.</returns>
        private IVsWindowFrame Open(VsLogicalView logicalView, IntPtr existingDocumentData, Guid specificEditor, string physicalView)
        {
            Tracer.VerifyNonNullArgument(logicalView, "logicalView");

            // Check to see if the file exists before we try to open it.
            if (!File.Exists(this.AbsolutePath))
            {
                Context.ShowErrorMessageBox(SconceStrings.FileDoesNotExist(this.AbsolutePath));
                return(null);
            }

            IVsWindowFrame windowFrame;
            Guid           logicalViewGuid   = logicalView.Value;
            Guid           editorTypeGuid    = specificEditor;
            bool           useSpecificEditor = (specificEditor != Guid.Empty);
            int            hr;

            // Get a IVsUIShellOpenDocument object so that we can use it to open the document.
            IVsUIShellOpenDocument vsUIShellOpenDocument = (IVsUIShellOpenDocument)this.ServiceProvider.GetServiceOrThrow(typeof(SVsUIShellOpenDocument), typeof(IVsUIShellOpenDocument), classType, "Open");

            // Open the document.
            if (useSpecificEditor)
            {
                hr = vsUIShellOpenDocument.OpenSpecificEditor(
                    0,
                    this.CanonicalName,
                    ref editorTypeGuid,
                    physicalView,
                    ref logicalViewGuid,
                    this.Caption,
                    (IVsUIHierarchy)this.Hierarchy,
                    this.HierarchyId,
                    existingDocumentData,
                    (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)Package.Instance,
                    out windowFrame);
            }
            else
            {
                hr = vsUIShellOpenDocument.OpenStandardEditor(
                    unchecked ((uint)__VSOSEFLAGS.OSE_ChooseBestStdEditor),
                    this.CanonicalName,
                    ref logicalViewGuid,
                    this.Caption,
                    (IVsUIHierarchy)this.Hierarchy,
                    this.HierarchyId,
                    existingDocumentData,
                    (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)Package.Instance,
                    out windowFrame);
            }

            string editorTypeName = useSpecificEditor ? "specific" : "standard";

            if (NativeMethods.Succeeded(hr))
            {
                Tracer.WriteLineInformation(classType, "Open", "Succeeded in opening '{0}' with a {1} editor.", this.AbsolutePath, editorTypeName);
                if (windowFrame != null)
                {
                    // Get the document cookie and cache it.
                    object pvar;
                    hr = windowFrame.GetProperty((int)__VSFPROPID.VSFPROPID_DocCookie, out pvar);
                    NativeMethods.ThrowOnFailure(hr);
                    // pvar is an int, but we need a uint. We get an error if we try to immediately cast to uint
                    // without first casting to an int.
                    uint cookie = unchecked ((uint)(int)pvar);
                    this.SetDocumentCookie(cookie);
                    Tracer.WriteLineInformation(classType, "Open", "Document '{0}' has a cookie value of {1}", this.AbsolutePath, cookie);

                    // Show the window frame of the open document. The documentation says we don't need to do this, but the reality is different.
                    hr = windowFrame.Show();
                    Tracer.Assert(NativeMethods.Succeeded(hr), "Error in IVsWindowFrame.Show(): 0x{0:x}", hr);

                    // Trace the running documents.
                    VsHelperMethods.TraceRunningDocuments();
                }
                else
                {
                    Tracer.Fail("Open succeeded but we were returned a null IVsWindowFrame so we can't show the document.");
                }
            }
            else if (hr == NativeMethods.OLE_E_PROMPTSAVECANCELLED)
            {
                Tracer.WriteLineInformation(classType, "Open", "The user canceled out of the open dialog box.");
            }
            else
            {
                Tracer.Fail("Failed to open '{0}' with a {1} editor. Hr=0x{2:x}", this.AbsolutePath, editorTypeName, hr);
                NativeMethods.ThrowOnFailure(hr);
            }

            return(windowFrame);
        }
Exemple #11
0
        /// <summary>
        /// Does the actual work of changing the caption after all of the verifications have been done
        /// that it's Ok to move the file.
        /// </summary>
        /// <param name="newCaption">The new caption.</param>
        /// <param name="newPath">The new absolute path.</param>
        public override void MoveNodeOnCaptionChange(string newCaption, string newPath)
        {
            string oldCaption            = this.Caption;
            string oldPath               = this.AbsolutePath;
            string oldRelativePath       = this.RelativePath;
            bool   updatedWindowCaptions = false;
            bool   removedNode           = false;
            Node   newNode               = null;

            // If we are currently selected, cache the value so we can restore the selection
            // after the addition.
            bool wasSelected = this.Selected;

            // Tell the environment to stop listening to file change events on the old file.
            using (FileChangeNotificationSuspender notificationSuspender = new FileChangeNotificationSuspender(oldPath))
            {
                // Make sure the environment says we can start the rename.
                if (!this.Hierarchy.AttachedProject.Tracker.CanRenameFile(oldPath, newPath))
                {
                    return;
                }

                // Move the file on the file system to match the new name.
                if (!this.IsVirtual && File.Exists(oldPath) && !File.Exists(newPath))
                {
                    Tracer.WriteLineInformation(classType, "MoveNodeOnCaptionChange", "Renaming the file '{0}' to '{1}'.", oldPath, newPath);
                    string newDirectoryName = Path.GetDirectoryName(newPath);
                    if (!Directory.Exists(newDirectoryName))
                    {
                        Directory.CreateDirectory(newDirectoryName);
                    }
                    File.Move(oldPath, newPath);
                }

                try
                {
                    // Update all of the windows that currently have this file opened in an editor.
                    this.UpdateOpenWindowCaptions(newCaption);
                    updatedWindowCaptions = true;

                    // We have to remove the node and re-add it so that we can have the sorting preserved.
                    // Also, if the extension has changed then we'll have to recreate a new type-specific
                    // FileNode. The easy way is to remove ourself from the project then tell the project
                    // to add an existing file.

                    string newRelativePath = PackageUtility.MakeRelative(this.Hierarchy.RootNode.AbsoluteDirectory, newPath);

                    // Remove ourself from the hierarchy.
                    this.Parent.Children.Remove(this);
                    removedNode = true;

                    // We have now been removed from the hierarchy. Do NOT call any virtual methods or
                    // methods that depend on our state after this point.

                    // Re-add ourself as a new incarnation (different object). Our life ends here.
                    newNode = this.Hierarchy.AddExistingFile(newRelativePath, true);

                    if (newNode != null)
                    {
                        // We need to set our hierarchy Id to match the new hierachy Id in case Visual Studio
                        // calls back into us for something.
                        this.SetHierarchyId(newNode.HierarchyId);

                        // Select the new node if we were previously selected.
                        if (wasSelected)
                        {
                            newNode.Select();
                        }

                        // Tell the RDT to rename the document.
                        Context.RunningDocumentTable.RenameDocument(oldPath, newPath, newNode.HierarchyId);
                    }
                }
                catch (Exception e)
                {
                    if (ErrorUtility.IsExceptionUnrecoverable(e))
                    {
                        throw;
                    }

                    // Rollback the file move
                    Tracer.WriteLineWarning(classType, "MoveNodeOnCaptionChange", "There was an error in renaming the document. Exception: {0}", e);
                    File.Move(newPath, oldPath);

                    // Remove the node that we just added.
                    if (newNode != null)
                    {
                        newNode.RemoveFromProject();
                    }

                    // Re-add a new node since we've already removed the old node.
                    if (removedNode || this.Parent == null)
                    {
                        newNode = this.Hierarchy.AddExistingFile(oldRelativePath, true);
                        this.SetHierarchyId(newNode.HierarchyId);
                        if (wasSelected)
                        {
                            newNode.Select();
                        }
                    }

                    // Rollback the caption update on open windows
                    if (updatedWindowCaptions)
                    {
                        this.UpdateOpenWindowCaptions(oldCaption);
                    }

                    // Rethrow the exception
                    throw;
                }

                // Tell the environment that we're done renaming the document.
                this.Hierarchy.AttachedProject.Tracker.OnFileRenamed(oldPath, newPath);

                // Update the property browser.
                IVsUIShell vsUIShell = (IVsUIShell)this.Hierarchy.ServiceProvider.GetServiceOrThrow(typeof(SVsUIShell), typeof(IVsUIShell), classType, "MoveNodeOnCaptionChange");
                vsUIShell.RefreshPropertyBrowser(0);
            }
        }
Exemple #12
0
        /// <summary>
        /// Saves the attached project in the specified encoding.
        /// </summary>
        /// <param name="encoding">The encoding of the file. If null, <see cref="Encoding.UTF8"/> is used.</param>
        /// <param name="forceSave">Indicates whether to ignore the attached project's dirty flag when determining whether to save.</param>
        /// <returns>true if successful; otherwise, false.</returns>
        public bool Save(Encoding encoding, bool forceSave)
        {
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }

            // If a project hasn't been attached yet, there's nothing to save.
            if (this.Project == null)
            {
                return(false);
            }

            // Check the dirty state of the project to see if we even need to save.
            if (!this.Project.IsDirty && !forceSave)
            {
                Tracer.WriteLineInformation(classType, "Save", "The project doesn't need to be saved.");
                return(true);
            }

            // At this point we know we have to save the project.
            string filePath = this.Project.FilePath;

            try
            {
                using (StreamWriter streamWriter = new StreamWriter(filePath, false, encoding))
                {
                    ProjectFileXmlWriter writer = new ProjectFileXmlWriter(streamWriter);
                    writer.WriteStartDocument();

                    // <VisualStudioProject>
                    writer.WriteStartElement(ElementNames.VisualStudioProject);

                    // <Project>
                    writer.WriteStartElement(this.ProjectElementName);
                    this.WriteProjectAttributes(writer);

                    // <BuildSettings>
                    BuildSettings buildSettings = this.Project.BuildSettings;
                    writer.WriteStartElement(ElementNames.BuildSettings);
                    this.WriteBuildSettingsAttributes(writer);
                    writer.WriteEndElement();

                    // <Configurations>
                    writer.WriteStartElement(ElementNames.Configurations);
                    foreach (ProjectConfiguration config in this.Project.ConfigurationProvider.ProjectConfigurations)
                    {
                        this.WriteConfigurationNode(writer, config);
                    }
                    writer.WriteEndElement();

                    // <References>
                    writer.WriteStartElement(this.ReferencesElementName);
                    foreach (ReferenceFileNode reference in this.Project.ReferencesNode.Children)
                    {
                        writer.WriteStartElement(this.ReferenceElementName);
                        writer.WriteAttributeString(AttributeNames.RelativePath, reference.RelativePath);
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();

                    // <Files>
                    writer.WriteStartElement(ElementNames.Files);
                    this.WriteFilesInNode(writer, this.Project.RootNode);
                    writer.WriteEndElement();

                    writer.WriteEndDocument();

                    // Clear the project's dirty state.
                    this.Project.ClearDirty();
                }
            }
            catch (Exception e)
            {
                if (!this.SilentFailures)
                {
                    string title   = Package.Instance.Context.NativeResources.GetString(ResId.IDS_E_PROJECTFILESAVE_TITLE, filePath);
                    string message = Package.Instance.Context.NativeResources.GetString(ResId.IDS_E_PROJECTFILESAVE, e.Message);
                    Package.Instance.Context.ShowErrorMessageBox(title, message);
                }
                Tracer.Fail("There was an error in saving the file {0}: {1}", filePath, e.ToString());
                return(false);
            }

            return(true);
        }