///<summary> /// Save the buffer as a file, using an asynchronous model ///</summary> public IAsyncResult BeginSaveAs(string filename, ProgressCallback progressCallback, AsyncCallback ac) { lock (LockObj) { if (!fileOperationsAllowed) { return(null); } saveFinishedEvent.Reset(); userSaveAsyncCallback = ac; SaveAsOperation so = new SaveAsOperation(this, filename, progressCallback, SaveAsAsyncCallback, useGLibIdle); // don't allow messing up with the buffer // while we are saving // ...ReadAllowed is set in SaveOperation // this.ReadAllowed = false; this.ModifyAllowed = false; this.FileOperationsAllowed = false; this.EmitEvents = false; if (fsw != null) { fsw.EnableRaisingEvents = false; } // start save thread Thread saveThread = new Thread(so.OperationThread); saveThread.IsBackground = true; saveThread.Start(); return(new ThreadedAsyncResult(so, saveFinishedEvent, false)); } }
protected override void DoOperation() { SaveAsOperation sao = new SaveAsOperation(byteBuffer, tempPath, this.progressCallback, null, false); stageReached = SaveStage.BeforeSaveAs; // Check for free space for final file // free space for temporary file is checked in sao.DoOperation() if (!CheckFreeSpace(Path.GetDirectoryName(byteBuffer.Filename), byteBuffer.fileBuf.Size)) { string msg = string.Format(Catalog.GetString("There is not enough free space on the device to save file '{0}'."), byteBuffer.Filename); throw new IOException(msg); } // Save ByteBuffer as a temp file sao.OperationThread(); if (sao.Result == ThreadedAsyncOperation.OperationResult.CaughtException) { throw sao.ThreadException; } else if (sao.Result == ThreadedAsyncOperation.OperationResult.Cancelled) { cancelled = true; } // if user hasn't cancelled, move temp file to // its final location if (!cancelled) { this.ActivateProgressReport(true); stageReached = SaveStage.BeforeDelete; // Delete here to fail early (before invalidating the byteBuffer) // if there are any issues. if (System.IO.File.Exists(savePath)) { System.IO.File.Delete(savePath); } // close the file, make sure that File Operations // are temporarily allowed lock (byteBuffer.LockObj) { // CloseFile invalidates the file buffer, // so make sure undo/redo data stays valid byteBuffer.MakePrivateCopyOfUndoRedo(); byteBuffer.FileOperationsAllowed = true; byteBuffer.CloseFile(); byteBuffer.FileOperationsAllowed = false; } stageReached = SaveStage.BeforeMove; System.IO.File.Move(tempPath, savePath); } }
///<summary> /// Called when an asynchronous Save As operation finishes ///</summary> void SaveAsAsyncCallback(IAsyncResult ar) { lock (LockObj) { SaveAsOperation so = (SaveAsOperation)ar.AsyncState; // re-allow buffer usage this.FileOperationsAllowed = true; // make sure Save As went smoothly before doing anything if (so.Result == SaveAsOperation.OperationResult.Finished) { // make sure data in undo redo are stored safely // because we are going to close the file MakePrivateCopyOfUndoRedo(); CloseFile(); LoadWithFile(so.SavePath); if (undoDeque.Count > 0) { SaveCheckpoint = undoDeque.PeekFront(); } else { SaveCheckpoint = null; } changedBeyondUndo = false; } else { // if cancelled or caught an exception // delete the file only if we have altered it if (so.StageReached != SaveAsOperation.SaveAsStage.BeforeCreate) { try { System.IO.File.Delete(so.SavePath); } catch (Exception e) { System.Console.WriteLine(e.Message); } } } // re-allow buffer usage this.ReadAllowed = true; this.ModifyAllowed = true; this.EmitEvents = true; if (fsw != null) { fsw.EnableRaisingEvents = true; } // notify the world about the changes EmitPermissionsChanged(); EmitChanged(); // if user provided a callback, call it now if (userSaveAsyncCallback != null) { userSaveAsyncCallback(ar); } // notify that Save As has finished saveFinishedEvent.Set(); } }