in ArchivedSamples/Source_Code_Control_Provider/C#/SccProviderService.cs [578:745]
public int QueryEditFiles([In] uint rgfQueryEdit, [In] int cFiles, [In] string[] rgpszMkDocuments, [In] uint[] rgrgf, [In] 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;
}