Beispiel #1
0
		private void PushUowOnUndoStack(FdoUnitOfWork newUow)
		{
			m_undoBundles.Push(newUow);
			Debug.Assert(m_countUnsavedBundles >= 0);
			m_countUnsavedBundles++;
		}
Beispiel #2
0
		/// <summary>
		/// This undo stack has a change that conflicts with itemToUndo if it has a redoable item with an earlier
		/// sequence number that is affected by redoing itemToRedo.
		/// </summary>
		internal bool HasConflictingRedoChanges(FdoUnitOfWork itemToRedo)
		{
			// Stack enumeration is in reverse order, so we get the first change we might redo first.
			foreach (var other in m_redoBundles)
			{
				// If it's equal we're comparing with ourself, which should not be considered a conflict!
				if (other.Sequence >= itemToRedo.Sequence)
					return false; // this and therefore all remaining changes are later than the one we are testing
				if (other.IsAffectedByRedoing(itemToRedo))
					return true;
			}
			return false;
		}
Beispiel #3
0
		/// <summary>
		/// Rollback the current UOW.
		///</summary>
		/// <param name='nDepth'>[Not used.]</param>
		/// <exception cref="InvalidOperationException">
		/// Thrown if not in the right state to do
		/// a rollback (in the data change phase of the UOW).
		/// </exception>
		public void Rollback(int nDepth)
		{
			if (this != m_uowService.ActiveUndoStack)
			{
				m_uowService.ActiveUndoStack.Rollback(nDepth);
				return;
			}
			if (m_uowService.CurrentProcessingState != UnitOfWorkService.FdoBusinessTransactionState.ProcessingDataChanges)
				throw new InvalidOperationException("Rollback not supported in the current state.");

			Debug.Assert(m_uowService.m_lock.IsWriteLockHeld, "Trying Rollback without write lock!");
			if (m_uowService.m_lock.IsWriteLockHeld)
				m_uowService.m_lock.ExitWriteLock();
			else
				Logger.WriteEvent("Trying to rollback without write lock!");

			m_currentBundle.Rollback();
			m_currentBundle = null;
			m_actionsToDoAtEndOfPropChanged.Clear(); // don't do them on some subsequent task
			m_uowService.CurrentProcessingState = UnitOfWorkService.FdoBusinessTransactionState.ReadyForBeginTask;
		}
Beispiel #4
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Raises the prop changed completed event.
		/// </summary>
		/// <param name="uow">The unit of work we are doing, undoing, or redoing.</param>
		/// <param name="fromUndoRedo">True if the method was called for an undo or
		/// redo, false for the original action.</param>
		/// ------------------------------------------------------------------------------------
		private void DoTasksForEndOfPropChanged(FdoUnitOfWork uow, bool fromUndoRedo)
		{
			var tasks = new List<Action>();
			if (!fromUndoRedo)
			{
				// These notifications must be sent only once.
				// In particular they must not be sent again if one of the tasks in the list makes a new UOW.
				// Since this method will execute at the end of such a task, we must make sure that there is
				// a fresh m_actionsToDoAtEndOfPropChanged for any such UOW so it will not see our list.
				tasks.AddRange(m_actionsToDoAtEndOfPropChanged);
				m_actionsToDoAtEndOfPropChanged.Clear();
			}
			tasks.AddRange(uow.ActionsToDoAtEndOfPropChanged);
			if (tasks.Count > 0)
			{
				m_ui.SynchronizeInvoke.Invoke(() =>
					{
						foreach (Action task in tasks)
							task();
					});
			}
		}
Beispiel #5
0
		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.Any())
				{
					var proj = (LangProject) m_currentBundle.DirtyObjects.ElementAt(0).Cache.LangProject;
					var 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;
				}
			}

			var oldCurrentBundle = m_currentBundle;
			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.
			DoTasksForEndOfPropChanged(oldCurrentBundle, false);
		}
Beispiel #6
0
		/// <summary>
		/// Begin a sequence of non-undoable actions.
		///</summary>
		public void BeginNonUndoableTask()
		{
			if (this != m_uowService.ActiveUndoStack)
			{
				m_uowService.ActiveUndoStack.BeginNonUndoableTask();
				return;
			}
			CheckNotProcessingDataChanges("Nested tasks are not supported.");
			CheckNotBroadcastingPropChanges("Can't start new task, while broadcasting PropChanges.");
			CheckNotInUndoRedo();
			m_uowService.CurrentProcessingState = UnitOfWorkService.FdoBusinessTransactionState.ProcessingDataChanges;
			m_uowService.m_lock.EnterWriteLock();
			m_currentBundle = new FdoNonUndoableUnitOfWork(m_uowService);
		}
Beispiel #7
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Clears all marks and bundles.
		/// </summary>
		/// ------------------------------------------------------------------------------------
		private void Clear()
		{
			m_currentBundle = null;
			ClearAllMarks();
			m_undoBundles.Clear();
			m_redoBundles.Clear();
		}
Beispiel #8
0
		public UndoStack(UnitOfWorkService uowService, IFdoUI ui)
		{
			m_uowService = uowService;
			m_ui = ui;
			m_undoBundles = new Stack<FdoUnitOfWork>();
			m_redoBundles = new Stack<FdoUnitOfWork>();
			m_currentBundle = null;

		}