/// ------------------------------------------------------------------------------------ /// <summary> /// Redo the action(s) in this object. This is overridden to do nothing in /// non-undoable unit of work, but may be called even from there in one special case. /// </summary> /// <returns> /// Cumulative result of redoing all the actions. If we succeeded, then this will /// be kuresSuccess. /// </returns> /// ------------------------------------------------------------------------------------ /// <summary> /// Redo the action(s) in this object. /// </summary> internal virtual UndoResult Redo() { // Because of the complexities of our undo/redo system, we need to do the redo // in multiple passes: // 1) Restores any created objects. // 2) Redo any actions that are data change actions. // 3) Fire any PropChanges. // 4) Redo any actions that are not data change actions (e.g., selection change actions) m_uowService.SuppressSelections = true; UndoResult result = UndoResult.kuresSuccess; try { // Do the first pass (Restores any created objects) foreach (IUndoAction undoAction in m_changes) { if (undoAction is IFirstPassRedo) { ((IFirstPassRedo)undoAction).FirstPassRedo(); } } // Do the second pass (Redo any actions that are data change actions) foreach (IUndoAction undoAction in m_changes) { if (undoAction.IsDataChange && !undoAction.Redo()) { // TODO: Undo any changes that have been redone return(UndoResult.kuresFailed); } } try { // Do the third pass (Fire any PropChanges) m_uowService.SendPropChangedNotifications(GetPropChangeInformation(false)); } catch (Exception e) { Logger.WriteEvent("Exception during PropChanges in Redo"); Logger.WriteError(e); result = UndoResult.kuresRefresh; } } finally { m_uowService.SuppressSelections = false; } // Do the fourth pass (Redo any actions that are not data change actions) foreach (IUndoAction undoAction in m_changes) { if (!undoAction.IsDataChange && !undoAction.Redo()) { // TODO: Undo any changes that have been redone return(UndoResult.kuresFailed); } } return(result); }
private void EndUndoTaskCommon(bool updateDateModified) { if (m_uowService.CurrentProcessingState != UnitOfWorkService.FdoBusinessTransactionState.ProcessingDataChanges) { throw new InvalidOperationException("Cannot end task that has not been started."); } if (updateDateModified) { // A generic side effect of all changes is to update DateModified. // Collect the objects we want to record the modify time on. Don't do each as found: // Updating them will add new dirtballs, which will mess up the DirtyObjects iterator. // Also, we don't need the overhead of updating an object repeatedly if it has several changes. var collector = new HashSet <ICmObjectInternal>(); foreach (var item in m_currentBundle.DirtyObjects) { item.CollectDateModifiedObject(collector); } // Don't update the modify time on new objects, it should be near enough, and Undo will fail // trying to restore the modify time on the deleted object. var newObjects = m_currentBundle.NewObjects; foreach (var dmObj in collector) { if (!newObjects.Contains(dmObj.Id) && !m_currentBundle.IsDateModifiedExplicitly(dmObj)) { dmObj.UpdateDateModified(); } } // Update the project DateModified, but only once every 2 minutes at most. if (m_currentBundle.DirtyObjects.Count() > 0) { LangProject proj = m_currentBundle.DirtyObjects.ElementAt(0).Cache.LangProject as LangProject; TimeSpan span = new TimeSpan(DateTime.Now.Ticks - proj.DateModified.Ticks); if (span.Minutes >= 2 || m_currentBundle.DirtyObjects.Contains(proj)) { proj.UpdateDateModifiedInternal(); } } } m_uowService.m_lock.ExitWriteLock(); m_uowService.CurrentProcessingState = UnitOfWorkService.FdoBusinessTransactionState.BroadcastingPropChanges; if (m_currentBundle.HasDataChange) { // Can't redo these now. // If m_currentBundle can't be finished well, // then it can all be rolled back ClearRedoStack(); PushUowOnUndoStack(m_currentBundle); m_currentBundle.SetAfterXml(); m_uowService.SuppressSelections = true; try { // Handle Step 2.B (PropChanged calls) here. // Do them here because we may not commit yet. // 2.B can be moved after the optional save, but then rethink the states. m_uowService.SendPropChangedNotifications(m_currentBundle.GetPropChangeInformation(false)); } finally { m_uowService.SuppressSelections = false; } } m_currentBundle = null; m_uowService.CurrentProcessingState = UnitOfWorkService.FdoBusinessTransactionState.ReadyForBeginTask; // Do this after we are back in a safe state to do a new UOW, if necessary. RaisePropChangedCompleted(false); }