示例#1
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);
            }
        }
示例#2
0
 /// <summary>
 /// Canonicalizes the specified path as a file path. If it should be canonicalized as a folder path
 /// then the subclass should override.
 /// </summary>
 /// <param name="absolutePath">The path to canonicalize.</param>
 /// <returns>The canonicalized path.</returns>
 protected virtual string CanonicalizePath(string absolutePath)
 {
     return(PackageUtility.CanonicalizeFilePath(absolutePath));
 }
示例#3
0
        /// <summary>
        /// Shows the Visual Studio open file dialog.
        /// </summary>
        /// <param name="dialogTitle">The title for the dialog box.</param>
        /// <param name="filter">The filter for the dialog.</param>
        /// <param name="initialDirectory">The initial starting directory. Can be null to use the current directory.</param>
        /// <returns>An array of paths to the chosen files or an empty array if the user canceled the dialog.</returns>
        public string[] ShowOpenFileDialog(string dialogTitle, string filter, string initialDirectory)
        {
            ArrayList fileNames  = new ArrayList();
            int       bufferSize = NativeMethods.MAX_PATH;

            // Get the HWND to use for the modal file dialog.
            IntPtr     hwnd;
            IVsUIShell uiShell = this.ServiceProvider.GetVsUIShell(classType, "ShowOpenFileDialog");

            NativeMethods.ThrowOnFailure(uiShell.GetDialogOwnerHwnd(out hwnd));

            // Create a native string buffer for the file name.
            IntPtr pwzFileName = Marshal.StringToHGlobalUni(new string('\0', bufferSize));

            try
            {
                // Fill in open file options structure.
                VSOPENFILENAMEW[] openFileOptions = new VSOPENFILENAMEW[1];
                openFileOptions[0].lStructSize   = (uint)Marshal.SizeOf(typeof(VSOPENFILENAMEW));
                openFileOptions[0].hwndOwner     = hwnd;
                openFileOptions[0].pwzDlgTitle   = dialogTitle;
                openFileOptions[0].pwzFileName   = pwzFileName;
                openFileOptions[0].nMaxFileName  = (uint)bufferSize;
                openFileOptions[0].pwzFilter     = filter;
                openFileOptions[0].pwzInitialDir = initialDirectory;
                openFileOptions[0].dwFlags       = (uint)(VsOpenFileDialogFlags.AllowMultiSelect);

                // Open the Visual Studio open dialog.
                int  hr       = uiShell.GetOpenFileNameViaDlg(openFileOptions);
                bool canceled = (hr == NativeMethods.OLE_E_PROMPTSAVECANCELLED);
                if (NativeMethods.Failed(hr) && !canceled)
                {
                    NativeMethods.ThrowOnFailure(hr);
                }

                // Get the file name(s).
                if (openFileOptions[0].pwzFileName != IntPtr.Zero && !canceled)
                {
                    // We want to get the entire buffered string because if multiple files were selected then it has
                    // the following format: directory\0file1\0file2\0...fileN\0\0. Note that it ends with two null
                    // terminators.
                    string rawDialogPath = Marshal.PtrToStringUni(openFileOptions[0].pwzFileName, bufferSize);

                    // These will hold our currently parsed values.
                    StringBuilder directory        = new StringBuilder();
                    StringBuilder fileName         = new StringBuilder();
                    bool          parsingDirectory = true;

                    // Walk over the raw string to pull out the directory and the file names.
                    for (int i = 0; i < rawDialogPath.Length; i++)
                    {
                        char c     = rawDialogPath[i];
                        char nextC = (i + 1 < rawDialogPath.Length ? rawDialogPath[i + 1] : '\0');

                        // If we've hit a null termination, then we have to stop parsing for a second and add an
                        // item to our array.
                        if (c != '\0')
                        {
                            if (parsingDirectory)
                            {
                                directory.Append(c);
                            }
                            else
                            {
                                fileName.Append(c);
                            }
                        }
                        else
                        {
                            if (parsingDirectory)
                            {
                                parsingDirectory = false;
                            }
                            else
                            {
                                // We've seen another file, so let's add the absolute path to our array.
                                string absolutePath = Path.Combine(directory.ToString(), fileName.ToString());
                                absolutePath = PackageUtility.CanonicalizeFilePath(absolutePath);
                                fileNames.Add(absolutePath);

                                // Clear the file name StringBuilder for the next round.
                                fileName.Length = 0;
                            }

                            // If we are at the double null termination then we can quit parsing.
                            if (nextC == '\0')
                            {
                                // If the user only selected one file, then our parsed directory should be the full file name.
                                if (fileNames.Count == 0)
                                {
                                    fileNames.Add(directory.ToString());
                                }
                                break;
                            }
                        }
                    }
                }
            }
            finally
            {
                // Release the string buffer.
                if (pwzFileName != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pwzFileName);
                }
            }

            return((string[])fileNames.ToArray(typeof(string)));
        }
示例#4
0
        //=========================================================================================
        // Constructors
        //=========================================================================================

        /// <summary>
        /// Static class initializer.
        /// </summary>
        static Tracer()
        {
            // Get the full path to the log file. We'll create a directory in the user's
            // temp directory for the Votive log. This is to fix SourceForge bug #1122213
            // where a non-administrator would have insufficient access to write to the
            // same directory as the assembly (which is Program Files by default).
            string tempDir = Path.Combine(Path.GetTempPath(), DirectoryName);

            if (!Directory.Exists(tempDir))
            {
                try
                {
                    Directory.CreateDirectory(tempDir);
                }
                catch (Exception e)
                {
                    initializationException = e;
                    return;
                }
            }
            logPath = Path.Combine(tempDir, FileName);

            // Delete the existing log file by creating a zero-length log file.
            if (File.Exists(logPath))
            {
                FileStream stream = null;
                try
                {
                    stream = File.Open(logPath, FileMode.Truncate, FileAccess.Write, FileShare.Write);
                }
                catch (Exception e)
                {
                    initializationException = e;
                    return;
                }
                finally
                {
                    if (stream != null)
                    {
                        stream.Close();
                    }
                }
            }

            // We'll use the default listener as our logger. Create it if it doesn't exist.
            DefaultTraceListener listener = (DefaultTraceListener)Trace.Listeners["Default"];

            if (listener == null)
            {
                listener = new DefaultTraceListener();
                Trace.Listeners.Add(listener);
            }
            listener.LogFileName = logPath;

            Trace.IndentSize = 0;
            Trace.AutoFlush  = true;

            try
            {
                // Write the first line to the trace log to make sure we can write to it.
                string firstLine = PackageUtility.SafeStringFormatInvariant("Trace started on {0}.", DateTime.Now.ToString(HeaderDateFormat, CultureInfo.InvariantCulture));
                Trace.WriteLine(firstLine);
            }
            catch (Exception e)
            {
                initializationException = e;
            }
        }
示例#5
0
        int IVsProject3.AddItem(uint itemidLoc, VSADDITEMOPERATION dwAddItemOperation, string pszItemName, uint cFilesToOpen, string[] rgpszFilesToOpen, IntPtr hwndDlgOwner, VSADDRESULT[] pResult)
        {
            bool canceled   = false;
            bool wereErrors = false;

            pResult[0] = VSADDRESULT.ADDRESULT_Failure;

            // Get the parent node to which it should be added.
            FolderNode parentNode = this.GetNode(itemidLoc, true) as FolderNode;

            if (parentNode == null)
            {
                string message = this.NativeResources.GetString(ResId.IDS_E_ADDITEMTOPROJECT, Path.GetFileName(this.FilePath));
                Context.ShowErrorMessageBox(message);
                Tracer.Fail("The specified parent {0} is not a FolderNode so we can't add an item to it.", itemidLoc);
                return(NativeMethods.E_UNEXPECTED);
            }

            // Loop through the files that are to be added and add them, one by one.
            foreach (string sourcePath in rgpszFilesToOpen)
            {
                string destPath  = null;
                Node   addedNode = null;

                switch (dwAddItemOperation)
                {
                case VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE:
                    destPath  = Path.Combine(parentNode.AbsoluteDirectory, pszItemName);
                    addedNode = this.AddCopyOfFile(sourcePath, destPath, out canceled);
                    break;

                case VSADDITEMOPERATION.VSADDITEMOP_OPENFILE:
                    if (PackageUtility.IsRelative(this.RootDirectory, sourcePath))
                    {
                        destPath  = PackageUtility.MakeRelative(this.RootDirectory, sourcePath);
                        addedNode = this.AddExistingFile(destPath, true);
                    }
                    else
                    {
                        destPath  = Path.Combine(parentNode.AbsoluteDirectory, Path.GetFileName(sourcePath));
                        addedNode = this.AddCopyOfFile(sourcePath, destPath, out canceled);
                    }
                    break;

                case VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE:
                    Tracer.Fail("NYI: VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE.");
                    throw new NotImplementedException("Linking to files is not supported yet.");

                case VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD:
                    Tracer.Fail("NYI: VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD.");
                    throw new NotImplementedException("Running a wizard is not supported yet.");

                default:
                    Tracer.Fail("Unknown VSADDDITEMOPERATION '{0}'", dwAddItemOperation);
                    throw new ArgumentException(PackageUtility.SafeStringFormatInvariant("The dwAddItemOperation contains an unknown and unsupported value '{0}'.", dwAddItemOperation), "dwAddItemOperation");
                }

                // There were errors if the node is still null at this point.
                wereErrors = (addedNode == null);
            }

            pResult[0] = (canceled ? VSADDRESULT.ADDRESULT_Cancel : (wereErrors ? VSADDRESULT.ADDRESULT_Failure : VSADDRESULT.ADDRESULT_Success));
            return(NativeMethods.S_OK);
        }
示例#6
0
 /// <summary>
 /// Canonicalizes the specified path as a directory path.
 /// </summary>
 /// <param name="absolutePath">The path to canonicalize.</param>
 /// <returns>The canonicalized path.</returns>
 protected override string CanonicalizePath(string absolutePath)
 {
     return(PackageUtility.CanonicalizeFilePath(absolutePath));
 }
        public static void TraceRunningDocuments()
        {
            // Get the RDT (Running Document Table)
            IVsRunningDocumentTable rdt = Package.Instance.Context.ServiceProvider.GetService(typeof(IVsRunningDocumentTable)) as IVsRunningDocumentTable;

            if (rdt == null)
            {
                Tracer.WriteLineWarning(classType, "TraceRunningDocuments", "Cannot get an instance of IVsRunningDocumentTable to use for enumerating the running documents.");
                return;
            }

            // Get the enumerator for the currently running documents.
            IEnumRunningDocuments enumerator;
            int hr = rdt.GetRunningDocumentsEnum(out enumerator);

            if (NativeMethods.Failed(hr))
            {
                Tracer.WriteLineWarning(classType, "TraceRunningDocuments", "Cannot get an instance of IEnumRunningDocuments to use for enumerating the running documents.");
                return;
            }

            // Enumerate.
            StringCollection traceLines = new StringCollection();

            uint[] cookies = new uint[1];
            uint   fetchCount;

            while (true)
            {
                hr = enumerator.Next(1, cookies, out fetchCount);
                if (NativeMethods.Failed(hr))
                {
                    Tracer.WriteLineWarning(classType, "TraceRunningDocuments", "The enumeration failed for the running documents. Hr=0x{0:X}", hr);
                    return;
                }

                if (fetchCount == 0)
                {
                    break;
                }

                uint cookie = cookies[0];

                // We shouldn't be getting a nil cookie.
                if (cookie == DocumentInfo.NullCookie)
                {
                    Tracer.WriteLineWarning(classType, "TraceRunningDocuments", "There is a null cookie value in the RDT, which shouldn't be happening.");
                }
                else
                {
                    // Now we have a document cookie, so let's get some information about it.
                    DocumentInfo docInfo = Package.Instance.Context.RunningDocumentTable.FindByCookie(cookie);
                    string       traceMessage;
                    if (docInfo == null)
                    {
                        traceMessage = PackageUtility.SafeStringFormatInvariant("The document with cookie '{0}' could not be found in the RDT. There's something weird going on.", cookie);
                    }
                    else
                    {
                        // Here's where we actually do the trace finally.
                        traceMessage = PackageUtility.SafeStringFormatInvariant("RDT document: Cookie={0} Path={1} IsOpen={2} IsDirty={3}", docInfo.Cookie, docInfo.AbsolutePath, docInfo.IsOpen, docInfo.IsDirty);
                    }

                    // We don't want to trace immediately because we want all of these lines to appear together. If we
                    // trace immediately, then the messages will be split up.
                    traceLines.Add(traceMessage);
                }
            }

            // Now trace all of the messages at once.
            foreach (string traceMessage in traceLines)
            {
                Tracer.WriteLine(classType, "TraceRunningDocuments", Tracer.Level.Information, traceMessage);
            }
        }