Beispiel #1
0
        private void UndoOp(DocumentModel doc, BaseOpMessage op, ITextEdit edit)
        {
            switch (op.MessageType)
            {
                case "insert":
                    var insert = (OpInsertMessage)op;
                    this.UndoInsert(doc, insert, edit);
                    break;

                case "delete":
                    var delete = (OpDeleteMessage)op;
                    this.UndoDelete(doc, delete, edit);
                    break;

                case "replace":
                    var replace = (OpReplaceMessage)op;
                    this.UndoReplace(doc, replace, edit);
                    break;
            }
        }
Beispiel #2
0
 /// <summary>
 /// Undoes a replace operation.
 /// </summary>
 /// <param name="model">The model.</param>
 private void UndoReplace(DocumentModel doc, OpReplaceMessage model, ITextEdit edit)
 {
     //doc.BlockEvent = true;
     var span = new Span(model.Index, model.Content.Length);
     edit.Replace(span, model.OldContent);
 }
Beispiel #3
0
 /// <summary>
 /// Undoes a delete operation.
 /// </summary>
 /// <param name="model">The model.</param>
 private void UndoDelete(DocumentModel doc, OpDeleteMessage model, ITextEdit edit)
 {
     //doc.BlockEvent = true;
     edit.Insert(model.Index, model.OldContent);
 }
Beispiel #4
0
 /// <summary>
 /// Undoes an insert operation.
 /// </summary>
 /// <param name="model">The model.</param>
 private void UndoInsert(DocumentModel doc, OpInsertMessage model, ITextEdit edit)
 {
     //doc.BlockEvent = true;
     var span = new Span(model.Index, model.Content.Length);
     edit.Delete(span);
 }
Beispiel #5
0
        private int RedoOp(DocumentModel doc, BaseOpMessage op, ITextEdit edit)
        {
            var len = 0;
            switch (op.MessageType)
            {
                case "insert":
                    var insert = (OpInsertMessage)op;
                    len = insert.Content.Length;
                    this.Insert(doc, insert, edit);
                    break;

                case "delete":
                    var delete = (OpDeleteMessage)op;
                    len = delete.Index - delete.End;
                    this.Delete(doc, delete, edit);
                    break;

                case "replace":
                    var replace = (OpReplaceMessage)op;
                    len = replace.OldContent.Length - replace.Content.Length;
                    this.Replace(doc, replace, edit);
                    break;
            }

            return len;
        }
Beispiel #6
0
        /// <summary>
        /// Performs a replace in a document.
        /// </summary>
        /// <param name="model">The model.</param>
        private void Replace(DocumentModel doc, OpReplaceMessage model, ITextEdit edit)
        {
            //doc.BlockEvent = true;
            var start = model.Index;
            var length = model.OldContent.Length;

            if (start > edit.Snapshot.Length - length)
            {
                start = edit.Snapshot.Length - length;
            }

            if (model.TickStamp == 0)
            {
                length = edit.Snapshot.Length;
            }

            var span = new Span(start, length);
            edit.Replace(span, model.Content);
        }
Beispiel #7
0
 /// <summary>
 /// Performs an insert in a document.
 /// </summary>
 /// <param name="model">The model.</param>
 private void Insert(DocumentModel doc, OpInsertMessage model, ITextEdit edit)
 {
     //doc.BlockEvent = true;
     var start = model.Index > edit.Snapshot.Length ? edit.Snapshot.Length : model.Index;
     edit.Insert(start, model.Content);
 }
Beispiel #8
0
        private int DoOp(DocumentModel doc, ITextEdit edit, BaseOpMessage op)
        {
            var len = 0;
            switch (op.MessageType)
            {
                case "insert":
                    var insert = op as OpInsertMessage;
                    len = insert.Content.Length;
                    doc.Changes.Add(insert);
                    this.Insert(doc, insert, edit);
                    break;

                case "delete":
                    var delete = op as OpDeleteMessage;
                    len = delete.Index - delete.End;
                    doc.Changes.Add(delete);
                    this.Delete(doc, delete, edit);
                    break;

                case "replace":
                    var replace = op as OpReplaceMessage;
                    len = replace.OldContent.Length - replace.Content.Length;
                    doc.Changes.Add(replace);
                    this.Replace(doc, replace, edit);
                    break;
            }

            return len;
        }
Beispiel #9
0
        /// <summary>
        /// Performs a delete in a document.
        /// </summary>
        /// <param name="model">The model.</param>
        private void Delete(DocumentModel doc, OpDeleteMessage model, ITextEdit edit)
        {
            //doc.BlockEvent = true;
            var len = model.End - model.Index;

            if (len > doc.View.TextBuffer.CurrentSnapshot.Length)
            {
                len = edit.Snapshot.Length;
            }

            var span = new Span(model.Index, len);
            edit.Delete(span);
        }
Beispiel #10
0
        /// <summary>
        /// Receives a share request.
        /// </summary>
        /// <param name="model">The model.</param>
        public void ReceiveShare(ReceiveShareMessage model)
        {
            bool accept = false;

            if (model.Sharer != this.UserName)
            {
                var msg = string.Format(
                    "{0} would like to share a document with you.  Accept?",
                    model.Sharer);

                var result = MessageBox.Show(
                        msg,
                        "Collaboration Invite",
                        MessageBoxButton.YesNo);

                if (result == MessageBoxResult.Yes)
                {
                    accept = true;
                }
            }
            else
            {
                accept = true;
            }

            if (accept)
            {
                // find/open the document
                var tuple = this.WindowService.OpenDocumentWindow(
                                    model.DocumentId);

                var view = tuple.Item2;

                var tick = this.WindowService.GetCurrentTick(model.OpId);

                var doc = new DocumentModel(tick)
                {
                    DocumentId = model.DocumentId,
                    FullPath = tuple.Item1,
                    OpId = model.OpId,
                    View = view,
                    Changed = (s, e) => TextChanged(s, e, model.DocumentId),
                    Closed = (s, e) => EndCollaboration(s, e, model.DocumentId)
                };

                this.Documents.Add(model.DocumentId, doc);

                this.ViewModel.Collaborations.Add(
                    new CollaborationsViewModel.Collaboration()
                    {
                        DocumentId = model.DocumentId,
                        OpId = model.OpId
                    });

                var joinMessage = new JoinCollaborationMessage()
                {
                    Service = "op",
                    MessageType = "join",
                    OpId = model.OpId,
                    User = this.UserName
                };

                this.SendMessage(joinMessage);

                // attach events and stuff
                view.TextBuffer.Changed += doc.Changed;
                view.Closed += doc.Closed;
            }
        }
Beispiel #11
0
        /// <summary>
        /// Resolves the operations.
        /// </summary>
        /// <param name="doc">The doc.</param>
        /// <param name="remote">The remote.</param>
        /// <param name="local">The local.</param>
        public static void Resolve(DocumentModel doc, BaseOpMessage remoteOp, BaseOpMessage localOp)
        {
            if (remoteOp is OpDeleteMessage)
            {
                var remote = remoteOp as OpDeleteMessage;
                Debug.WriteLine("Remote: {0} Delete", remote.User);
                if (localOp is OpDeleteMessage)
                {
                    var local = localOp as OpDeleteMessage;
                    int noOpLength = 0;

                    if (remote.Index < local.Index)
                    {
                        // no overlap, remote OK as is, local needs modifications
                        local.Index = local.Index - remote.ReplacementLength;
                    }
                    else if (remote.Index + remote.ReplacementLength < local.Index + local.ReplacementLength)
                    {
                        // remote del at lower index reaches into locally
                        // applied del, local del reaches further out
                        // --> shorten remote del appropriately, move and
                        // shorten local del left
                        remote.Length = (remote.Index + remote.ReplacementLength) - local.Index;
                        local.Length = (remote.Index + remote.ReplacementLength) - local.Index;
                        local.Index = remote.Index;
                    }
                    else if ((remote.Index + remote.ReplacementLength >= local.Index + local.ReplacementLength))
                    {
                        // remote del at lower index, remote del fully extends
                        // over local del
                        // --> shorten remote by local length
                        // make local no-op
                        remote.ReplacementLength = remote.ReplacementLength - local.ReplacementLength;

                        // TODO: verify this...
                        local.Index = remote.Index;
                        local.ReplacementLength = noOpLength;
                    }
                    else if (remote.Index == local.Index)
                    {
                        if (remote.Index + remote.ReplacementLength < local.Index + local.ReplacementLength)
                        {
                            // start indeces are equal, remote is shorter
                            // --> make remote no-op
                            remote.ReplacementLength = noOpLength;
                            // --> shorten local to only delete
                            // non-overlapping region
                            local.ReplacementLength = local.ReplacementLength - remote.ReplacementLength;
                        }
                        else if (remote.Index + remote.ReplacementLength == local.Index + local.ReplacementLength)
                        {
                            // same endIndex, same deletion
                            // --> make remote op be no-op
                            remote.ReplacementLength = noOpLength;
                            // --> make local op appear as no-op
                            local.ReplacementLength = noOpLength;
                        }
                        else if (remote.Index + remote.ReplacementLength > local.Index + local.ReplacementLength)
                        {
                            // remote del extends over local del
                            // --> shorten remote del by length of local del,
                            // index/offset does not need to be updated
                            remote.ReplacementLength = remote.ReplacementLength - local.ReplacementLength;
                            // --> make local del appear as no-op
                            local.ReplacementLength = noOpLength;
                        }
                    }
                    else if (remote.Index > local.Index)
                    {
                        if (remote.Index > local.Index + local.ReplacementLength)
                        {
                            // move remote delete left by length of local deletion
                            remote.Index = remote.Index - local.ReplacementLength;
                        }
                        else if (remote.Index + remote.ReplacementLength < local.Index + local.ReplacementLength)
                        {
                            //remote is fully contained in/overlapping with local del
                            // --> remote is no-op
                            remote.ReplacementLength = noOpLength;
                            // --> local needs to be shortened by length of remote
                            local.ReplacementLength = local.ReplacementLength - remote.ReplacementLength;
                        }
                        else if (remote.Index < local.Index + local.ReplacementLength)
                        {
                            // remote del starts within local del, but extends further
                            // --> shorten remote by overlap and move left
                            // to index of local del
                            remote.ReplacementLength = remote.ReplacementLength - (local.Index + local.ReplacementLength) - remote.Index;
                        }
                    }
                }
                else if (localOp is OpInsertMessage)
                {
                    var local = localOp as OpInsertMessage;
                    if (remote.Index < localOp.Index)
                    {
                        if (remote.Index + remote.ReplacementLength < local.Index)
                        {
                            // remote remains unchanged, deletion happens fully
                            // before local insertion
                            // local insert needs to be moved left by full length of deletion
                            local.Index -= remote.ReplacementLength;
                        }
                        else if (remote.Index + remote.ReplacementLength >= local.Index)
                        {
                            // TODO ???
                        }
                        else if (remote.Index >= local.Index)
                        {
                            // remote del needs to be moved right by full length of insertion
                            remote.Index += local.Content.Length;
                        }
                    }
                }
            }
            else if (remoteOp is OpInsertMessage)
            {
                var remote = remoteOp as OpInsertMessage;
                if (localOp is OpInsertMessage)
                {
                    var local = localOp as OpInsertMessage;
                    if (remote.Index < local.Index)
                    {
                        local.Index += remote.Content.Length;
                    }
                    else if (remote.Index == local.Index)
                    {
                        var compare = local.User.CompareTo(remote.User);
                        if (compare < 0)
                        {
                            remote.Index += local.Content.Length;
                        }
                        else
                        {
                            local.Index += remote.Content.Length;
                        }
                    }
                    else if (remote.Index > local.Index)
                    {
                        remote.Index += local.Content.Length;
                    }
                }
                else if (localOp is OpDeleteMessage)
                {
                    var local = localOp as OpDeleteMessage;
                    if (remote.Index <= localOp.Index)
                    {
                        localOp.Index += remote.Content.Length;
                    }
                    else if (remote.Index > localOp.Index)
                    {
                        if (remote.Index > local.Index + local.ReplacementLength)
                        {
                            remote.Index -= local.ReplacementLength;
                        }
                        else if (remote.Index <= local.Index + local.ReplacementLength)
                        {
                            // TODO ???
                        }
                    }
                }
            }
        }