protected virtual int SaveAs(string newFileName)
{
Debug.Assert(!String.IsNullOrEmpty(newFileName), "Cannot save project file for an empty or null file name");
if (String.IsNullOrEmpty(newFileName))
{
throw new ArgumentNullException("newFileName");
}
newFileName = newFileName.Trim();
string errorMessage = String.Empty;
if (newFileName.Length > NativeMethods.MAX_PATH)
{
errorMessage = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.PathTooLong, CultureInfo.CurrentUICulture), newFileName);
}
else
{
string fileName = String.Empty;
try
{
fileName = Path.GetFileNameWithoutExtension(newFileName);
}
// We want to be consistent in the error message and exception we throw. fileName could be for example #¤&%"¤&"% and that would trigger an ArgumentException on Path.IsRooted.
catch (ArgumentException)
{
errorMessage = SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture);
}
if (errorMessage.Length == 0)
{
// If there is no filename or it starts with a leading dot issue an error message and quit.
// For some reason the save as dialog box allows to save files like "......ext"
if (String.IsNullOrEmpty(fileName) || fileName[0] == '.')
{
errorMessage = SR.GetString(SR.FileNameCannotContainALeadingPeriod, CultureInfo.CurrentUICulture);
}
else if (Utilities.ContainsInvalidFileNameChars(newFileName))
{
errorMessage = SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture);
}
else
{
string url = Path.GetDirectoryName(newFileName);
string oldUrl = Path.GetDirectoryName(this.Url);
if (!NativeMethods.IsSamePath(oldUrl, url))
{
errorMessage = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.SaveOfProjectFileOutsideCurrentDirectory, CultureInfo.CurrentUICulture), this.ProjectFolder);
}
}
}
}
if (errorMessage.Length > 0)
{
// If it is not called from an automation method show a dialog box.
if (!Utilities.IsInAutomationFunction(this.Site))
{
string title = null;
OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL;
OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
VsShellUtilities.ShowMessageBox(this.Site, title, errorMessage, icon, buttons, defaultButton);
return VSConstants.OLE_E_PROMPTSAVECANCELLED;
}
throw new InvalidOperationException(errorMessage);
}
string oldName = this.filename;
IVsSolution solution = this.Site.GetService(typeof(IVsSolution)) as IVsSolution;
Debug.Assert(solution != null, "Could not retrieve the solution form the service provider");
if (solution == null)
{
throw new InvalidOperationException();
}
int canRenameContinue = 0;
ErrorHandler.ThrowOnFailure(solution.QueryRenameProject(this, this.filename, newFileName, 0, out canRenameContinue));
if (canRenameContinue == 0)
{
return VSConstants.OLE_E_PROMPTSAVECANCELLED;
}
SuspendFileChanges fileChanges = new SuspendFileChanges(this.Site, oldName);
fileChanges.Suspend();
try
{
// Save the project file and project file related properties.
this.SaveMSBuildProjectFileAs(newFileName);
this.SetProjectFileDirty(false);
// TODO: If source control is enabled check out the project file.
//Redraw.
this.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_Caption, 0);
ErrorHandler.ThrowOnFailure(solution.OnAfterRenameProject(this, oldName, this.filename, 0));
IVsUIShell shell = this.Site.GetService(typeof(SVsUIShell)) as IVsUIShell;
Debug.Assert(shell != null, "Could not get the ui shell from the project");
if (shell == null)
{
throw new InvalidOperationException();
}
ErrorHandler.ThrowOnFailure(shell.RefreshPropertyBrowser(0));
}
finally
{
fileChanges.Resume();
}
return VSConstants.S_OK;
}