Пример #1
0
        protected override bool UpdateTarget(ReceiveContext context)
        {
            bool update = base.UpdateTarget(context);

            InkSheetModel sheet = this.Target as InkSheetModel;

            if (sheet == null)
            {
                return(update);
            }

            ArrayList deleting = new ArrayList(this.StrokeIds.Length);

            foreach (Stroke existing in sheet.Ink.Strokes)
            {
                if (existing.ExtendedProperties.DoesPropertyExist(StrokeIdExtendedProperty))
                {
                    if (Array.IndexOf(this.StrokeIds, existing.ExtendedProperties[StrokeIdExtendedProperty].Data) >= 0)
                    {
                        deleting.Add(existing.Id);
                    }
                }
            }

            int[] ids = ((int[])deleting.ToArray(typeof(int)));
            using (Strokes strokes = sheet.Ink.CreateStrokes(ids)) {
                StrokesEventArgs args = new StrokesEventArgs(ids);
                sheet.OnInkDeleting(args);
                sheet.Ink.DeleteStrokes(strokes);
                sheet.OnInkDeleted(args);
            }

            return(update);
        }
Пример #2
0
        protected override bool UpdateTarget(ReceiveContext context)
        {
            bool update = base.UpdateTarget(context);

            InkSheetModel sheet = this.Target as InkSheetModel;

            if (sheet == null)
            {
                return(update);
            }

            using (Synchronizer.Lock(sheet.Ink.Strokes.SyncRoot)) {
                int[] newIds;
                if (this.SavedInks.Length == 1)
                {
                    this.LoadInkIntoTarget(sheet, this.SavedInks[0], out newIds);
                }
                else
                {
                    ArrayList ids = new ArrayList();
                    foreach (byte[] saved in this.SavedInks)
                    {
                        this.LoadInkIntoTarget(sheet, saved, out newIds);
                        ids.AddRange(newIds);
                    }
                    newIds = ((int[])ids.ToArray(typeof(int)));
                }

                // Notify the renderers that a new set of strokes have been created.
                sheet.OnInkAdded(new StrokesEventArgs(newIds));
            }

            return(update);
        }
Пример #3
0
        /// <summary>
        /// Performs a deep copy of the given SheetModel.
        /// If the given sheetmodel is not an InkSheet, then returns itself.
        /// </summary>
        /// <param name="s">The SheetModel to copy</param>
        /// <returns>The given sheetmodel if not an InkSheetModel, otherwise a deep copy of the InkSheetModel</returns>
        protected SheetModel InkSheetDeepCopyHelper(SheetModel s)
        {
            using (Synchronizer.Lock(s.SyncRoot)) {
                InkSheetModel t;
                // Only copy InkSheetModels
                if (s is InkSheetModel)
                {
                    if (s is RealTimeInkSheetModel)
                    {
                        // Make a deep copy of the SheetModel
                        t = new RealTimeInkSheetModel(Guid.NewGuid(), s.Disposition | SheetDisposition.Remote, s.Bounds, ((RealTimeInkSheetModel)s).Ink.Clone());
                        using (Synchronizer.Lock(t.SyncRoot)) {
                            ((RealTimeInkSheetModel)t).CurrentDrawingAttributes = ((RealTimeInkSheetModel)s).CurrentDrawingAttributes;
                        }
                    }
                    else
                    {
                        // Make a deep copy of the SheetModel
                        t = new InkSheetModel(Guid.NewGuid(), s.Disposition, s.Bounds, ((InkSheetModel)s).Ink.Clone());
                    }
                    // This is a new object so add it to the local references
                    Message.AddLocalRef(t.Id, t);
                    return(t);
                }
            }

            return(s);
        }
Пример #4
0
            protected override object SetUpMember(int index, object member)
            {
                SheetModel sheet = ((SheetModel)member);

                // Add the SheetMatch to the collection of matches
                using (Synchronizer.Lock(sheet.SyncRoot)) {
                    using (Synchronizer.Lock(this.m_Owner.m_DestSlide.SyncRoot)) {
                        if (sheet is RealTimeInkSheetModel)
                        {
                            // Add the sheet
                            RealTimeInkSheetModel m = new RealTimeInkSheetModel(Guid.NewGuid(), sheet.Disposition, sheet.Bounds);
                            this.m_Owner.m_DestSlide.AnnotationSheets.Add(m);

                            // Add the sheet match
                            SheetMatch toAdd = SheetMatch.ForSheet(this.m_Owner.m_Sender, sheet, m);
                            this.m_Owner.m_SheetMatches.Add(toAdd);
                        }
                        else if (sheet is InkSheetModel)
                        {
                            // Add the sheet
                            InkSheetModel m = new InkSheetModel(Guid.NewGuid(), sheet.Disposition, sheet.Bounds);
                            this.m_Owner.m_DestSlide.AnnotationSheets.Add(m);

                            // Add the sheet match
                            SheetMatch toAdd = SheetMatch.ForSheet(this.m_Owner.m_Sender, sheet, m);
                            this.m_Owner.m_SheetMatches.Add(toAdd);
                        }
                    }
                }

                return(null);
            }
Пример #5
0
        private void LoadInkIntoTarget(InkSheetModel sheet, Ink extracted, out int[] ids)
        {
            Ink restored = extracted;

            using (Synchronizer.Lock(sheet.Ink.Strokes.SyncRoot)) {
                ids = new int[restored.Strokes.Count];

                for (int i = 0; i < ids.Length; i++)
                {
                    Stroke stroke = restored.Strokes[i];

                    // Remove any strokes that have the same remote Id as the new one.
                    // Unfortunately, because the InkSheetUndoService cannot preserve stroke referential identity,
                    // we must do a full search each time and cannot simply keep a table.
                    if (stroke.ExtendedProperties.DoesPropertyExist(InkSheetMessage.StrokeIdExtendedProperty))
                    {
                        object id = stroke.ExtendedProperties[InkSheetMessage.StrokeIdExtendedProperty].Data;
                        foreach (Stroke existing in sheet.Ink.Strokes)
                        {
                            if (existing.ExtendedProperties.DoesPropertyExist(InkSheetMessage.StrokeIdExtendedProperty))
                            {
                                if (id.Equals(existing.ExtendedProperties[InkSheetMessage.StrokeIdExtendedProperty].Data))
                                {
                                    StrokesEventArgs args = new StrokesEventArgs(new int[] { existing.Id });
                                    sheet.OnInkDeleting(args);
                                    sheet.Ink.DeleteStroke(existing);
                                    sheet.OnInkDeleted(args);
                                }
                            }
                        }
                    }

                    // The stroke has no association with the current Ink object.
                    // Therefore, we have to recreate it by copying the raw packet data.
                    // This first requires recreating the TabletPropertyDescriptionCollection,
                    // which, for some stupid reason, must be done manually for lack of a better API.
                    TabletPropertyDescriptionCollection properties = new TabletPropertyDescriptionCollection();
                    foreach (Guid property in stroke.PacketDescription)
                    {
                        properties.Add(new TabletPropertyDescription(property, stroke.GetPacketDescriptionPropertyMetrics(property)));
                    }

                    // Create a new stroke from the raw packet data.
                    Stroke created = sheet.Ink.CreateStroke(stroke.GetPacketData(), properties);

                    // Copy the DrawingAttributes and all application data
                    // (especially the StrokesIdExtendedProperty) to the new stroke.
                    created.DrawingAttributes = stroke.DrawingAttributes;
                    foreach (ExtendedProperty prop in stroke.ExtendedProperties)
                    {
                        created.ExtendedProperties.Add(prop.Id, prop.Data);
                    }

                    ids[i] = created.Id;
                }
            }
        }
Пример #6
0
            /// <summary>
            /// Handle the button being clicked
            /// </summary>
            /// <param name="args">The event args</param>
            protected override void OnClick(EventArgs args)
            {
                if (this.m_Slide == null)
                {
                    return;
                }

                using (Synchronizer.Lock(this.m_Slide.SyncRoot)) {
                    InkSheetModel inks = null;

                    // TODO: This code is duplicated in InkSheetAdapter.  Extract to a "ActiveInkAnnotationSheet" property of the SlideModel.
                    // Find the *top-most* *local* InkSheetModel in the annotation layer.
                    for (int i = m_Slide.AnnotationSheets.Count - 1; i >= 0; i--)
                    {
                        SheetModel sheet = m_Slide.AnnotationSheets[i];
                        if ((sheet.Disposition & SheetDisposition.Remote) != 0)
                        {
                            continue;
                        }

                        if (sheet is InkSheetModel)
                        {
                            inks = ((InkSheetModel)sheet);
                        }
                        //else if (sheet is EditableSheetModel ) {
                        //    ///only erase the sheet model if the user made it
                        //    ///(i.e. it is editable. If this is sent from another
                        //    ///person, don't erase it).
                        //    EditableSheetModel edit_sheet = (EditableSheetModel)sheet;
                        //    if (edit_sheet.IsEditable) {
                        //        m_Slide.AnnotationSheets.Remove(sheet);
                        //    }
                        //}
                    }

                    if (inks != null)
                    {
                        using (Synchronizer.Lock(inks.SyncRoot)) {
                            Strokes strokes = inks.Ink.Strokes;
                            using (Synchronizer.Lock(strokes.SyncRoot)) {
                                int[] ids = new int[inks.Ink.Strokes.Count];
                                for (int j = 0; j < strokes.Count; j++)
                                {
                                    ids[j] = strokes[j].Id;
                                }

                                StrokesEventArgs sea = new StrokesEventArgs(ids);
                                inks.OnInkDeleting(sea);
                                inks.Ink.DeleteStrokes();
                                inks.OnInkDeleted(sea);
                            }
                        }
                    }
                }

                base.OnClick(args);
            }
Пример #7
0
        public SSInkSheetNetworkService(SendingQueue sender, PresentationModel presentation, DeckModel deck, SlideModel slide, InkSheetModel sheet, SheetMessage.SheetCollection selector) : base(sender, presentation, deck, slide, sheet, selector)
        {
            this.m_Sheet = sheet;

            this.m_Sheet.InkAdded    += new StrokesEventHandler(this.HandleInkAdded);
            this.m_Sheet.InkDeleting += new StrokesEventHandler(this.HandleInkDeleting);

            this.SendExistingInk();
        }
Пример #8
0
        public InkSheetMatch(EventQueue sender, InkSheetModel srcSheet, InkSheetModel dstSheet) : base(sender, srcSheet, dstSheet)
        {
            this.m_SourceSheet = srcSheet;
            this.m_DestSheet   = dstSheet;

            this.m_SourceSheet.InkAdded    += new StrokesEventHandler(this.HandleInkAdded);
            this.m_SourceSheet.InkDeleting += new StrokesEventHandler(this.HandleInkDeleting);

            this.SendExistingInk();
        }
Пример #9
0
        public InkSheetRenderer(SlideDisplayModel display, InkSheetModel sheet) : base(display, sheet)
        {
            this.m_Sheet = sheet;

            this.m_Renderer = new Renderer();

            this.m_Sheet.Changed["Selection"].Add(new PropertyEventHandler(this.HandleSelectionChanged));
            this.m_Sheet.InkAdded   += new StrokesEventHandler(this.HandleInkAdded);
            this.m_Sheet.InkDeleted += new StrokesEventHandler(this.HandleInkDeleted);

            this.SlideDisplay.Changed["InkTransform"].Add(new PropertyEventHandler(this.HandleInkTransformChanged));
            this.HandleInkTransformChanged(this.SlideDisplay, null);
        }
Пример #10
0
        public InkSheetUndoService(EventQueue dispatcher, UndoModel undo, DeckModel deck, SlideModel slide, InkSheetModel sheet) : base(undo, deck, slide, sheet)
        {
            this.m_EventQueue = dispatcher;
            this.m_InkSheet   = sheet;

            this.m_Ignore = new ArrayList();

            //Ignore any sheets with the Remote flag
            if ((this.m_InkSheet.Disposition & SheetDisposition.Remote) == 0)
            {
                this.m_HandleInkChangedDelegate = new HandleInkChangedDelegate(this.HandleInkChanged);
                this.m_InkSheet.InkAdded       += new StrokesEventHandler(this.HandleInkAdded);
                this.m_InkSheet.InkDeleting    += new StrokesEventHandler(this.HandleInkDeleting);
            }
        }
Пример #11
0
        /// <summary>
        /// Construct the InkSheetWebService, this class listens for strokes to finish
        /// and sends them across the network
        /// </summary>
        /// <param name="sender">The queue to use</param>
        /// <param name="presentation">The presentation model</param>
        /// <param name="deck">The deck model</param>
        /// <param name="slide">The slide model</param>
        /// <param name="sheet">The sheet model</param>
        /// <param name="selector">The sheet collection we are part of</param>
        public InkSheetWebService(SendingQueue sender, PresentationModel presentation, DeckModel deck, SlideModel slide, SheetModel sheet, SheetMessage.SheetCollection selector)
            : base(sender, presentation, deck, slide, sheet, selector)
        {
            // Keep track of our sheet
            this.m_Sheet = (InkSheetModel)sheet;

            // Get the slide ID
            using (Synchronizer.Lock(slide.SyncRoot)) {
                m_SlideID = slide.Id;
            }

            // Set Events
            this.m_Sheet.InkAdded += new StrokesEventHandler(this.HandleInkAdded);
//            this.m_Sheet.InkDeleting += new StrokesEventHandler(this.HandleInkDeleting);
        }
Пример #12
0
        public InkSheetNetworkService(SendingQueue sender, PresentationModel presentation, DeckModel deck, SlideModel slide, InkSheetModel sheet, SheetMessage.SheetCollection selector) : base(sender, presentation, deck, slide, sheet, selector)
        {
            this.m_Sheet = sheet;
            using (Synchronizer.Lock(slide.SyncRoot)) {
                m_SlideID = slide.Id;
            }

            this.m_Sheet.InkAdded    += new StrokesEventHandler(this.HandleInkAdded);
            this.m_Sheet.InkDeleting += new StrokesEventHandler(this.HandleInkDeleting);

            Group receivers = Group.AllParticipant;

            if ((deck.Disposition & (DeckDisposition.StudentSubmission | DeckDisposition.QuickPoll)) != 0)
            {
                receivers = Group.Submissions;
            }

            this.SendExistingInk(receivers);
        }
Пример #13
0
 public InkSheetStrokesAddedMessage(InkSheetModel sheet, Guid slideId, SheetCollection selector, Ink ink) : base(sheet, selector)
 {
     this.SavedInks = new byte[][] { ink.Save() };
     SlideId        = slideId;
 }
Пример #14
0
 public InkSheetInformationMessage(InkSheetModel sheet, SheetCollection selector) : base(sheet, selector)
 {
 }
Пример #15
0
        /// <summary>
        /// Erases strokes that overlap the cursor.
        /// </summary>
        /// <param name="sender">The real time stylus associated with the notification</param>
        /// <param name="data">The notification data</param>
        /// <seealso cref="EraserPlugin.StylusDown"/>
        /// <seealso cref="EraserPlugin.Packets"/>
        /// <seealso cref="EraserPlugin.StylusUp"/>
        private void HandlePackets(RealTimeStylus sender, StylusDataBase data)
        {
            using (Synchronizer.Lock(this)) {
                // Ignore the strokes if the eraser stylus is not selected,
                // and if the stylus is not inverted.
                if (this.Eraser == null && !data.Stylus.Inverted)
                {
                    return;
                }

                // Ignore if a touch input
                if (m_TouchSupported)
                {
                    try {
                        if (sender.GetTabletFromTabletContextId(data.Stylus.TabletContextId).DeviceKind == TabletDeviceKind.Touch)
                        {
                            return;
                        }
                    }
                    catch {
                        m_TouchSupported = false;
                    }
                }

                // Ignore the strokes if no ink sheet is selected.
                InkSheetModel sheet = this.InkSheetModel;
                if (sheet == null)
                {
                    return;
                }

                // Convert the X and Y coordinates of the data,
                // which are defined to be at offsets [i] and [i+1],
                // to an array of Points.
                Debug.Assert(data.Count % data.PacketPropertyCount == 0);
                Point[] points = new Point[data.Count / data.PacketPropertyCount];
                for (int i = 0, j = 0, il = data.Count, inc = data.PacketPropertyCount; i < il; i += inc, j++)
                {
                    points[j] = new Point(data[i], data[i + 1]);
                }

                // Convert the ink points to pixels so we can
                // ignore the ones that are outside the slide view area.
                // This is done all at once to conserve resources used by the Graphics object.
                Point[] pixels = points;
                using (Synchronizer.Lock(this.m_Display.SyncRoot))
                    using (Graphics g = this.m_Display.CreateGraphics())
                        this.m_Renderer.InkSpaceToPixel(g, ref pixels);

                // Prevent anyone else from accessing the ink concurrently.
                using (Synchronizer.Lock(this.InkSheetModel.Ink.Strokes.SyncRoot)) {
                    // Iterate through each point through which the cursor has passed.
                    for (int i = 0, il = points.Length; i < il; i++)
                    {
                        // Don't erase anything when the cursor is outside of the
                        // slide viewing area.  This prevents users from accidentally
                        // erasing strokes they can't see, especially when using the
                        // slide zoom feature.
                        if (!this.m_DisplayBounds.Contains(pixels[i]))
                        {
                            continue;
                        }

                        // Find all strokes within some radius from the cursor.
                        Strokes erased = sheet.Ink.HitTest(points[i], ERASER_RADIUS);

                        // If any strokes were found, erase them.
                        if (erased.Count > 0)
                        {
                            // Get the list of stroke IDs in order to send an event
                            int[] ids = new int[erased.Count];
                            for (int j = 0; j < ids.Length; j++)
                            {
                                ids[j] = erased[j].Id;
                            }

                            // We must first warn listeners that the strokes are about to
                            // be deleted, because after they're deleted, no information
                            // about them can be recovered.  This is used to send
                            // network events and to store undo information.
                            sheet.OnInkDeleting(new StrokesEventArgs(ids));

                            // Delete the erased strokes.
                            sheet.Ink.DeleteStrokes(erased);

                            // Inform listeners that the strokes have actually been deleted.
                            // This causes slide displays to refresh.
                            sheet.OnInkDeleted(new StrokesEventArgs(ids));
                        }
                    }
                }
            }
        }
Пример #16
0
 public InkSheetStrokesDeletingMessage(InkSheetModel sheet, SheetCollection selector, string[] strokeIds) : base(sheet, selector)
 {
     this.StrokeIds = ((string[])strokeIds.Clone());
 }
Пример #17
0
        private void HandleSlideChanged(object sender, PropertyEventArgs args)
        {
            using (Synchronizer.Lock(this)) {
                SlideModel slide;
                using (Synchronizer.Lock(this.m_SlideDisplay.SyncRoot)) {
                    slide = this.m_SlideDisplay.Slide;
                    // Release the reader lock immediately, because it is not possible (or at least easy)
                    // to guarantee consistent locking order between the SlideDisplayModel and the SlideModel.
                    // Most of the SheetRenderer classes will obtain a lock on the SlideModel *first*
                    // and the SlideDisplayModel *second* because they react to changes in the slide;
                    // but that order is not possible here.
                }

                if (slide == null)
                {
                    this.m_Adaptee.InkSheetModel         = null;
                    this.m_Adaptee.RealTimeInkSheetModel = null;
                }

                else
                {
                    using (Synchronizer.Lock(slide.SyncRoot)) {
                        try {
                            InkSheetModel         inks = null;
                            RealTimeInkSheetModel rti  = null;

                            // TODO: This code is duplicated in SlideToolBarButtons.ClearInkSheetToolBarButton.  Extract to a "ActiveInkAnnotationSheet" property of the SlideModel.
                            // Find the *top-most* InkSheetModel and RealTimeInkSheetModel in the annotation layer.
                            foreach (SheetModel sheet in slide.AnnotationSheets)
                            {
                                // Only consider local sheets.
                                if ((sheet.Disposition & SheetDisposition.Remote) != 0)
                                {
                                    continue;

                                    // RealTimeInkSheetModels get priority.
                                }
                                else if (sheet is RealTimeInkSheetModel)
                                {
                                    inks = rti = ((RealTimeInkSheetModel)sheet);

                                    // Regular InkSheetModels are our second choice.
                                }
                                else if (sheet is InkSheetModel)
                                {
                                    inks = ((InkSheetModel)sheet);
                                    rti  = null;

                                    // Only consider the *top-most* non-remote sheet (the last one in the collection).
                                }
                                else
                                {
                                    continue;
                                }
                            }

                            if (inks == null && rti == null)
                            {
                                // If the slide does not have an ink annotation sheet, create one.
                                inks = rti = new RealTimeInkSheetModel(Guid.NewGuid(), SheetDisposition.All, Rectangle.Empty);

                                // Add it to the slide.
                                slide.AnnotationSheets.Add(rti);
                            }

                            // Start collecting ink into the InkSheetModel's Ink object
                            // (after the sheet is added to the slide, so renderers don't get out of sync).
                            // Also start sending events to InkSheetModel.RealTimeInk.
                            this.m_Adaptee.InkSheetModel         = rti == null ? inks : rti;
                            this.m_Adaptee.RealTimeInkSheetModel = rti;
                        }

                        catch {
                            // We were unable to get an Ink annotation sheet, so disable inking.
                            this.m_Adaptee.InkSheetModel         = null;
                            this.m_Adaptee.RealTimeInkSheetModel = null;
                            throw;
                        }
                    }
                }
            }
        }