123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- using System;
- using System.Threading;
- namespace PaintDotNet.Measurement
- {
- /// <summary>
- /// A HistoryMemento is generally used to save part of the state of the Document
- /// so that an action that is yet to be performed can be undone at a later time.
- /// For example, if you are going to paint in a certain region, you first create a
- /// HistoryMemento that saves the contents of the area you are painting to. Then you
- /// paint. Then you push the history action on to the history stack.
- ///
- /// Using the HistoryMementoData class you can serialize your data to disk so that it
- /// doesn't fester in memory. There are important rules to follow here though:
- /// 1. Don't hold a reference to a Layer. Store a reference to the DocumentWorkspace and
- /// the layer's index instead, and access it via Workspace.Document.Layers[index].
- /// 2. The exception to #1 is if you are deleting a layer. But you should use
- /// DeleteLayerHistoryMemento for that. If you need to delete a layer as part of a
- /// compound action, use CompoundHistoryMemento in conjunction with
- /// DeleteLayerHistoryMemento.
- /// 3. To generalize, avoid serializing something unless you're replacing or deleting it.
- /// (and by 'serializing' I mean 'putting it in your HistoryMementoData class')
- /// It is better to hold a 'navigation reference' as opposed to a real reference.
- /// An example of a 'navigation reference' is listed in #1, where we don't store a ref
- /// to the layer itself but we store the information needed to navigate to it.
- /// The reasoning for this is made clear if you consider the following case. Assume you
- /// are holding on to a layer reference ("private Layer theLayer;"). Next, assume that
- /// the layer is deleted. Then the deletion is undone. The new layer in memory is not
- /// the layer you have a reference to even though they hold the same data. Changes made
- /// to one do not show up in the other one. Put another way, history actions should
- /// store large objects and their locations "by value," and not "by reference."
- /// </summary>
- public abstract class HistoryMemento
- {
- private string name;
- public string Name
- {
- get
- {
- return this.name;
- }
- set
- {
- this.name = value;
- }
- }
- private ImageResource image;
- public ImageResource Image
- {
- get
- {
- return this.image;
- }
- set
- {
- this.image = value;
- }
- }
- protected int id;
- private static int nextId = 0;
- public int ID
- {
- get
- {
- return this.id;
- }
- set
- {
- this.id = value;
- }
- }
- private Guid seriesGuid = Guid.Empty;
- public Guid SeriesGuid
- {
- get
- {
- return this.seriesGuid;
- }
- set
- {
- this.seriesGuid = value;
- }
- }
- private PersistedObject<HistoryMementoData> historyMementoData = null;
- /// <summary>
- /// Gets or sets the HistoryMementoData associated with this HistoryMemento.
- /// </summary>
- /// <remarks>
- /// Setting this property will immediately serialize the given object to disk.
- /// </remarks>
- protected HistoryMementoData Data
- {
- get
- {
- if (historyMementoData == null)
- {
- return null;
- }
- else
- {
- return (HistoryMementoData)historyMementoData.Object;
- }
- }
- set
- {
- this.historyMementoData = new PersistedObject<HistoryMementoData>(value, false);
- }
- }
- /// <summary>
- /// Ensures that the memory held by the Data property is serialized to disk and
- /// freed from memory.
- /// </summary>
- public void Flush()
- {
- if (historyMementoData != null)
- {
- historyMementoData.Flush();
- }
- OnFlush();
- }
- protected virtual void OnFlush()
- {
- }
- /// <summary>
- /// This will perform the necessary work required to undo an action.
- /// Note that the returned HistoryMemento should have the same ID.
- /// </summary>
- /// <returns>
- /// Returns a HistoryMemento that can be used to redo the action.
- /// Note that this property should hold: undoAction = undoAction.PerformUndo().PerformUndo()
- /// </returns>
- protected abstract HistoryMemento OnUndo();
- /// <summary>
- /// This method ensures that the returned HistoryMemento has the appropriate ID tag.
- /// </summary>
- /// <returns>Returns a HistoryMemento that can be used to redo the action.
- /// The ID of this HistoryMemento will be the same as the object that this
- /// method was called on.</returns>
- public HistoryMemento PerformUndo()
- {
- HistoryMemento ha = OnUndo();
- ha.ID = this.ID;
- ha.SeriesGuid = this.SeriesGuid;
- return ha;
- }
- public HistoryMemento(string name, ImageResource image)
- {
- SystemLayer.Tracing.LogFeature("HM(" + GetType().Name + ")");
- this.name = name;
- this.image = image;
- this.id = Interlocked.Increment(ref nextId);
- }
- }
- }
|