async Task SaveTask() { // suspend type service "check all file loop" since we have already a parsed document. // Or at least one that updates "soon". try { // Freeze the file change events. There can be several such events, and sending them all together // is more efficient FileService.FreezeEvents(); if (Window.ViewContent.IsViewOnly || !Window.ViewContent.IsDirty) { return; } if (!Window.ViewContent.IsFile) { await Window.ViewContent.Save(); return; } if (IsUntitled) { await SaveAs(); } else { try { FileService.RequestFileEdit((FilePath)Window.ViewContent.ContentName, true); } catch (Exception ex) { MessageService.ShowError(GettextCatalog.GetString("The file could not be saved."), ex.Message, ex); } FileAttributes attr = FileAttributes.ReadOnly | FileAttributes.Directory | FileAttributes.Offline | FileAttributes.System; if (!File.Exists((string)Window.ViewContent.ContentName) || (File.GetAttributes((string)window.ViewContent.ContentName) & attr) != 0) { await SaveAs(); } else { string fileName = Window.ViewContent.ContentName; // save backup first if (IdeApp.Preferences.CreateFileBackupCopies) { await Window.ViewContent.Save(fileName + "~"); FileService.NotifyFileChanged(fileName + "~"); } DocumentRegistry.SkipNextChange(fileName); await Window.ViewContent.Save(fileName); FileService.NotifyFileChanged(fileName); OnSaved(EventArgs.Empty); } } } finally { // Send all file change notifications FileService.ThawEvents(); // Set the file time of the current document after the file time of the written file, to prevent double file updates. // Note that the parsed document may be overwritten by a background thread to a more recent one. var doc = parsedDocument; if (doc != null) { string fileName = Window.ViewContent.ContentName; try { // filename could be null if the user cancelled SaveAs and this is a new & unsaved file if (fileName != null) { doc.LastWriteTimeUtc = File.GetLastWriteTimeUtc(fileName); } } catch (Exception e) { doc.LastWriteTimeUtc = DateTime.UtcNow; LoggingService.LogWarning("Exception while getting the write time from " + fileName, e); } } } }
async Task SaveTask() { // suspend type service "check all file loop" since we have already a parsed document. // Or at least one that updates "soon". var fileController = controller as FileDocumentController; try { // Freeze the file change events. There can be several such events, and sending them all together // is more efficient FileService.FreezeEvents(); if (controller.IsViewOnly || !controller.HasUnsavedChanges) { return; } if (fileController == null) { await controller.Save(); return; } if (IsNewDocument) { await SaveAs(); } else { var fileName = fileController.FilePath; try { FileService.RequestFileEdit(fileName, true); } catch (Exception ex) { MessageService.ShowError(GettextCatalog.GetString("The file could not be saved."), ex.Message, ex); } FileAttributes attr = FileAttributes.ReadOnly | FileAttributes.Directory | FileAttributes.Offline | FileAttributes.System; if (!File.Exists(fileName) || (File.GetAttributes(fileName) & attr) != 0) { await SaveAs(); } else { var allFiles = controller.GetDocumentFiles().ToList(); foreach (var file in allFiles) { DocumentRegistry.SkipNextChange(file); } await controller.Save(); if (IdeApp.Preferences.CreateFileBackupCopies) { foreach (var file in allFiles) { try { File.Copy(file, file + "~"); } catch (Exception ex) { LoggingService.LogError("Backup copy could not be created", ex); } } } // Force a change notification. This is needed for FastCheckNeedsBuild to be updated // when saving before a build, for example. FileService.NotifyFilesChanged(allFiles); Saved?.Invoke(this, EventArgs.Empty); } } } finally { // Send all file change notifications FileService.ThawEvents(); } }