Beispiel #1
0
 async Task RemoveRepresentation(Type repType, ModelRepresentation representation)
 {
     if (lastChangedRepresentation == representation && linkedModels.Count > 0)
     {
         // Make sure there is at lease one representation with the latest data
         var otherRep = representations.Values.FirstOrDefault(r => r != representation);
         if (otherRep == null)
         {
             // Even though there are other models sharing the same data, none of their
             // representations is loaded. Load one of them now, so that we can copy to it the data of the
             // representation being deleted.
             var otherModel = linkedModels [0];
             otherRep = GetRepresentationUnlinked(otherModel.RepresentationType);                          // Force the creation of the rep
         }
         try {
             await otherRep.WaitHandle.WaitAsync();
             await Synchronize(otherRep, true);
         } finally {
             otherRep.WaitHandle.Release();
         }
         lock (changeLock) {
             if (lastChangedRepresentation == representation || changeVersion < otherRep.CurrentVersion)
             {
                 lastChangedRepresentation = otherRep;
                 changeVersion             = otherRep.CurrentVersion;
             }
         }
     }
     representations.Remove(repType);
 }
Beispiel #2
0
            public async Task <ModelRepresentation> GetRepresentation(Type type)
            {
                ModelRepresentation existingRep = null;
                ModelRepresentation representation;

                try {
                    await dataLock.WaitAsync();

                    if (!representations.TryGetValue(type, out representation))
                    {
                        existingRep                      = representations.Values.FirstOrDefault();
                        representations [type]           = representation = (ModelRepresentation)Activator.CreateInstance(type);
                        representation.DocumentModelData = this;
                        if (existingRep != null)
                        {
                            // The requested representation is new and there are other representations around which may contain
                            // changes. Get existing data from them.
                            await existingRep.WaitHandle.WaitAsync();

                            // Ensure internal data structures are initialized
                            representation.CreateNew();
                            await representation.InternalCopyFrom(existingRep);
                        }
                    }
                } finally {
                    if (existingRep != null)
                    {
                        existingRep.WaitHandle.Release();
                    }
                    dataLock.Release();
                }

                return(representation);
            }
Beispiel #3
0
        public async Task Load()
        {
            CheckInitialized();
            modelRepresentation = await GetRepresentationAsync();

            await modelRepresentation.Load();
        }
Beispiel #4
0
 public void NotifyChanged(ModelRepresentation representation)
 {
     lock (changeLock) {
         lastChangedRepresentation     = representation;
         representation.CurrentVersion = ++changeVersion;
     }
     RaiseChangedEvent(representation.GetType());
 }
Beispiel #5
0
 protected override async Task OnCopyFrom(ModelRepresentation other)
 {
     if (other is FileModelRepresentation file)
     {
         await SetContent(file.GetContent());
     }
     else
     {
         throw new InvalidOperationException($"Can't copy data from model of type {other.GetType ()} into a model of type {GetType ()}");
     }
 }
Beispiel #6
0
            public void NotifyHasUnsavedChanges(ModelRepresentation representation)
            {
                var repType = representation.GetType();

                foreach (var m in linkedModels)
                {
                    if (m.RepresentationType == repType)
                    {
                        m.RaiseHasUnsavedChangesEvent();
                    }
                }
            }
        internal async Task InternalCopyFrom(ModelRepresentation other)
        {
            try {
                FreezeChangeEvent();

                // Capture the copied version now. If the copied object changes during the copy, the version
                // will increase, so a subsequent synchronize call will bring the additional changes.
                CurrentVersion = other.CurrentVersion;
                IsLoaded       = true;

                await OnCopyFrom(other);

                HasUnsavedChanges = other.HasUnsavedChanges;
            } finally {
                ThawChangeEvent(false);
            }
        }
Beispiel #8
0
        internal async Task RaiseRepresentationChangeEvent()
        {
            if (modelRepresentation == null)
            {
                return;
            }

            var newRep = await GetRepresentationAsync();

            if (newRep != modelRepresentation)
            {
                modelRepresentation = newRep;
                try {
                    OnRepresentationChanged();
                } catch (Exception ex) {
                    LoggingService.LogInternalError("OnRepresentationChanged failed", ex);
                }
                RaiseChangeEvent();
            }
        }
Beispiel #9
0
            async Task Synchronize(ModelRepresentation targetRep, bool dataLocked)
            {
                ModelRepresentation sourceModel = null;
                int currentChangeVersion;

                lock (changeLock) {
                    sourceModel          = lastChangedRepresentation;
                    currentChangeVersion = changeVersion;
                }

                if (targetRep.CurrentVersion == currentChangeVersion || sourceModel == null || sourceModel == targetRep)
                {
                    return;                     // Not changed
                }
                try {
                    // Any operation that requires the lock of several representation must take
                    // the model lock first, to avoid deadlocks
                    if (!dataLocked)
                    {
                        await dataLock.WaitAsync();

                        await targetRep.WaitHandle.WaitAsync();

                        await sourceModel.WaitHandle.WaitAsync();
                    }

                    await targetRep.InternalCopyFrom(sourceModel);
                } finally {
                    if (!dataLocked)
                    {
                        dataLock.Release();
                        targetRep.WaitHandle.Release();
                        sourceModel.WaitHandle.Release();
                    }
                }
                RaiseChangedEvent(targetRep.GetType());
            }
Beispiel #10
0
 public Task Synchronize(ModelRepresentation targetRep)
 {
     return(Synchronize(targetRep, false));
 }
Beispiel #11
0
            internal async Task Relink(DocumentModel model, DocumentModelData newData)
            {
                bool newDataLocked = false, representationLocked = false;
                ModelRepresentation representation = null;
                var repType = model.RepresentationType;
                ModelRepresentation modelRepresentationToDispose = null;

                var modelsToNotify = new List <DocumentModel> ();

                await dataLock.WaitAsync();

                try {
                    representations.TryGetValue(repType, out representation);
                    await representation.WaitHandle.WaitAsync();

                    representationLocked = true;

                    linkedModels = linkedModels.Remove(model);

                    var modelsForRep = linkedModels.Where(m => m.RepresentationType == repType).ToList();
                    if (modelsForRep.Count > 0)
                    {
                        // If there is more than one model using this representation then the representation
                        // has to be cloned, since it can't be shared anymore
                        var representationCopy = (ModelRepresentation)Activator.CreateInstance(representation.GetType());
                        await representationCopy.InternalCopyFrom(representation);

                        representationCopy.DocumentModelData = this;
                        representations [repType]            = representationCopy;
                        foreach (var m in modelsForRep)
                        {
                            modelsToNotify.Add(m);
                        }
                    }
                    else
                    {
                        await RemoveRepresentation(repType, representation);
                    }

                    if (newData != null)
                    {
                        await newData.dataLock.WaitAsync();

                        newDataLocked = true;

                        // If there are other models using the same representation, we'll have to notify them that
                        // the representation has changed
                        if (newData.representations.TryGetValue(repType, out modelRepresentationToDispose))
                        {
                            modelsToNotify.AddRange(newData.linkedModels.Where(m => m.RepresentationType == repType));
                        }

                        newData.linkedModels = newData.linkedModels.Add(model);
                        model.Data           = newData;
                        newData.representations [repType] = representation;
                        representation.DocumentModelData  = newData;

                        // Register that this new representation is the latest version.
                        // If there are other representations, they will get the new data after a Synchronize call.
                        newData.NotifyChanged(representation);
                    }
                } finally {
                    dataLock.Release();
                    if (representationLocked)
                    {
                        representation.WaitHandle.Release();
                    }
                    if (newDataLocked)
                    {
                        newData.dataLock.Release();
                    }
                }

                foreach (var m in modelsToNotify)
                {
                    m.RaiseRepresentationChangeEvent().Ignore();
                }

                if (modelRepresentationToDispose != null)
                {
                    modelRepresentationToDispose.OnDispose().Ignore();
                }
            }
Beispiel #12
0
 /// <summary>
 /// Saves the data to disk
 /// </summary>
 /// <returns>The save.</returns>
 public async Task Save()
 {
     CheckInitialized();
     await ModelRepresentation.Save();
 }
 protected abstract Task OnCopyFrom(ModelRepresentation other);