public void btnEdit_ClickTest()
 {
     DlgQueryEditCheckedInFile target = new DlgQueryEditCheckedInFile("Dummy.txt");
     MethodInfo method = typeof(DlgQueryEditCheckedInFile).GetMethod("btnEdit_Click", BindingFlags.NonPublic | BindingFlags.Instance);
     method.Invoke(target, new object[] {null, null} );
     Assert.AreEqual(target.Answer, DlgQueryEditCheckedInFile.qecifEditInMemory);
 }
        /// <summary>
        /// Called by projects and editors before modifying a file
        /// The function allows the source control systems to take the necessary actions (checkout, flip attributes)
        /// to make the file writable in order to allow the edit to continue
        ///
        /// There are a lot of cases to deal with during QueryEdit/QuerySave. 
        /// - called in commmand line mode, when UI cannot be displayed
        /// - called during builds, when save shoudn't probably be allowed
        /// - called during projects migration, when projects are not open and not registered yet with source control
        /// - checking out files may bring new versions from vss database which may be reloaded and the user may lose in-memory changes; some other files may not be reloadable
        /// - not all editors call QueryEdit when they modify the file the first time (buggy editors!), and the files may be already dirty in memory when QueryEdit is called
        /// - files on disk may be modified outside IDE and may have attributes incorrect for their scc status
        /// - checkouts may fail
        /// The sample provider won't deal with all these situations, but a real source control provider should!
        /// </summary>
        public int QueryEditFiles([InAttribute] uint rgfQueryEdit, [InAttribute] int cFiles, [InAttribute] string[] rgpszMkDocuments, [InAttribute] uint[] rgrgf, [InAttribute] VSQEQS_FILE_ATTRIBUTE_DATA[] rgFileInfo, out uint pfEditVerdict, out uint prgfMoreInfo)
        {
            // Initialize output variables
            pfEditVerdict = (uint)tagVSQueryEditResult.QER_EditOK;
            prgfMoreInfo = 0;

            // In non-UI mode just allow the edit, because the user cannot be asked what to do with the file
            if (_sccProvider.InCommandLineMode())
            {
                return VSConstants.S_OK;
            }

            try 
            {
                //Iterate through all the files
                for (int iFile = 0; iFile < cFiles; iFile++)
                {
                     
                    uint fEditVerdict = (uint)tagVSQueryEditResult.QER_EditNotOK;
                    uint fMoreInfo = 0;

                    // Because of the way we calculate the status, it is not possible to have a 
                    // checked in file that is writtable on disk, or a checked out file that is read-only on disk
                    // A source control provider would need to deal with those situations, too
                    SourceControlStatus status = GetFileStatus(rgpszMkDocuments[iFile]);
                    bool fileExists = File.Exists(rgpszMkDocuments[iFile]);
                    bool isFileReadOnly = false;
                    if (fileExists)
                    {
                        isFileReadOnly = (( File.GetAttributes(rgpszMkDocuments[iFile]) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly);
                    }

                    // Allow the edits if the file does not exist or is writable
                    if (!fileExists || !isFileReadOnly)
                    {
                        fEditVerdict = (uint)tagVSQueryEditResult.QER_EditOK;
                    }
                    else
                    {
                        // If the IDE asks about a file that was already approved for in-memory edit, allow the edit without asking the user again
                        if (_approvedForInMemoryEdit.ContainsKey(rgpszMkDocuments[iFile].ToLower()))
                        {
                            fEditVerdict = (uint)tagVSQueryEditResult.QER_EditOK;
                            fMoreInfo = (uint)(tagVSQueryEditResultFlags.QER_InMemoryEdit);
                        }
                        else
                        {
                            switch (status)
                            {
                                case SourceControlStatus.scsCheckedIn:
                                    if ((rgfQueryEdit & (uint)tagVSQueryEditFlags.QEF_ReportOnly) != 0)
                                    {
                                        fMoreInfo = (uint)(tagVSQueryEditResultFlags.QER_EditNotPossible | tagVSQueryEditResultFlags.QER_ReadOnlyUnderScc);
                                    }
                                    else
                                    {
                                        DlgQueryEditCheckedInFile dlgAskCheckout = new DlgQueryEditCheckedInFile(rgpszMkDocuments[iFile]);
                                        if ((rgfQueryEdit & (uint)tagVSQueryEditFlags.QEF_SilentMode) != 0)
                                        {
                                            // When called in silent mode, attempt the checkout
                                            // (The alternative is to deny the edit and return QER_NoisyPromptRequired and expect for a non-silent call)
                                            dlgAskCheckout.Answer = DlgQueryEditCheckedInFile.qecifCheckout;
                                        }
                                        else
                                        {
                                            dlgAskCheckout.ShowDialog();
                                        }

                                        if (dlgAskCheckout.Answer == DlgQueryEditCheckedInFile.qecifCheckout)
                                        {
                                            // Checkout the file, and since it cannot fail, allow the edit
                                            CheckoutFileAndRefreshProjectGlyphs(rgpszMkDocuments[iFile]);
                                            fEditVerdict = (uint)tagVSQueryEditResult.QER_EditOK;
                                            fMoreInfo = (uint)tagVSQueryEditResultFlags.QER_MaybeCheckedout;
                                            // Do not forget to set QER_Changed if the content of the file on disk changes during the query edit
                                            // Do not forget to set QER_Reloaded if the source control reloads the file from disk after such changing checkout.
                                        }
                                        else if (dlgAskCheckout.Answer == DlgQueryEditCheckedInFile.qecifEditInMemory)
                                        {
                                            // Allow edit in memory
                                            fEditVerdict = (uint)tagVSQueryEditResult.QER_EditOK;
                                            fMoreInfo = (uint)(tagVSQueryEditResultFlags.QER_InMemoryEdit);
                                            // Add the file to the list of files approved for edit, so if the IDE asks again about this file, we'll allow the edit without asking the user again
                                            // UNDONE: Currently, a file gets removed from _approvedForInMemoryEdit list only when the solution is closed. Consider intercepting the 
                                            // IVsRunningDocTableEvents.OnAfterSave/OnAfterSaveAll interface and removing the file from the approved list after it gets saved once.
                                            _approvedForInMemoryEdit[rgpszMkDocuments[iFile].ToLower()] = true;
                                        }
                                        else
                                        {
                                            fEditVerdict = (uint)tagVSQueryEditResult.QER_NoEdit_UserCanceled;
                                            fMoreInfo = (uint)(tagVSQueryEditResultFlags.QER_ReadOnlyUnderScc | tagVSQueryEditResultFlags.QER_CheckoutCanceledOrFailed);
                                        }

                                    }
                                    break;
                                case SourceControlStatus.scsCheckedOut: // fall through
                                case SourceControlStatus.scsUncontrolled:
                                    if (fileExists && isFileReadOnly)
                                    {
                                        if ((rgfQueryEdit & (uint)tagVSQueryEditFlags.QEF_ReportOnly) != 0)
                                        {
                                            fMoreInfo = (uint)(tagVSQueryEditResultFlags.QER_EditNotPossible | tagVSQueryEditResultFlags.QER_ReadOnlyNotUnderScc);
                                        }
                                        else
                                        {
                                            bool fChangeAttribute = false;
                                            if ((rgfQueryEdit & (uint)tagVSQueryEditFlags.QEF_SilentMode) != 0)
                                            {
                                                // When called in silent mode, deny the edit and return QER_NoisyPromptRequired and expect for a non-silent call)
                                                // (The alternative is to silently make the file writable and accept the edit)
                                                fMoreInfo = (uint)(tagVSQueryEditResultFlags.QER_EditNotPossible | tagVSQueryEditResultFlags.QER_ReadOnlyNotUnderScc | tagVSQueryEditResultFlags.QER_NoisyPromptRequired );
                                            }
                                            else
                                            {
                                                // This is a controlled file, warn the user
                                                IVsUIShell uiShell = (IVsUIShell)_sccProvider.GetService(typeof(SVsUIShell));
                                                Guid clsid = Guid.Empty;
                                                int result = VSConstants.S_OK;
                                                string messageText = Resources.ResourceManager.GetString("QEQS_EditUncontrolledReadOnly");
                                                string messageCaption = Resources.ResourceManager.GetString("ProviderName");
                                                if (uiShell.ShowMessageBox(0, ref clsid,
                                                                    messageCaption,
                                                                    String.Format(CultureInfo.CurrentUICulture, messageText, rgpszMkDocuments[iFile]),
                                                                    string.Empty,
                                                                    0,
                                                                    OLEMSGBUTTON.OLEMSGBUTTON_YESNO,
                                                                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
                                                                    OLEMSGICON.OLEMSGICON_QUERY,
                                                                    0,        // false = application modal; true would make it system modal
                                                                    out result) == VSConstants.S_OK
                                                    && result == (int)DialogResult.Yes)
                                                {
                                                    fChangeAttribute = true;
                                                }
                                            }

                                            if (fChangeAttribute)
                                            {
                                                // Make the file writable and allow the edit
                                                File.SetAttributes(rgpszMkDocuments[iFile], FileAttributes.Normal);
                                                fEditVerdict = (uint)tagVSQueryEditResult.QER_EditOK;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        fEditVerdict = (uint)tagVSQueryEditResult.QER_EditOK;
                                    }
                                    break;
                            }
                        }
                    }

                    // It's a bit unfortunate that we have to return only one set of flags for all the files involved in the operation
                    // The edit can continue if all the files were approved for edit
                    prgfMoreInfo |= fMoreInfo;
                    pfEditVerdict |= fEditVerdict;
                }
            }
            catch(Exception)
            {
                // If an exception was caught, do not allow the edit
                pfEditVerdict = (uint)tagVSQueryEditResult.QER_EditNotOK;
                prgfMoreInfo = (uint)tagVSQueryEditResultFlags.QER_EditNotPossible;
            }

            return VSConstants.S_OK;
        }
 public void ConstructorTest()
 {
     DlgQueryEditCheckedInFile target = new DlgQueryEditCheckedInFile("Dummy.txt");
     Assert.IsNotNull(target, "DlgQueryEditCheckedInFile cannot be created");
 }