public RealTimeInkSheetDataMessage(RealTimeInkSheetModel sheet, int stylusId, int strokeId, int[] packets) : base(sheet.Id) { this.StylusId = stylusId; this.StrokeId = strokeId; this.Packets = packets; }
/// <summary> /// Performs a deep copy of the given SheetModel and resets the disposition to remote. /// This seems to be a little more complicated than it needs to be because the disposition is read only. /// If the given sheetmodel is an InkSheet or an editable sheet, it is copied, otherwise, it returns itself. /// </summary> /// <param name="s">The SheetModel to copy</param> /// <returns>A deep copy of an InkSheet or an Editable Sheet, otherwise, itself</returns> public static SheetModel SheetDeepRemoteCopyHelper(SheetModel s) { using (Synchronizer.Lock(s.SyncRoot)) { SheetModel t = null; // Only copy InkSheetModels if (s is InkSheetModel || s is EditableSheetModel) { 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 if (s is InkSheetModel) { // Make a deep copy of the SheetModel t = new InkSheetModel(Guid.NewGuid(), s.Disposition | SheetDisposition.Remote, s.Bounds, ((InkSheetModel)s).Ink.Clone()); } else if (s is EditableSheetModel) { t = (EditableSheetModel)((EditableSheetModel)s).CloneToRemote(); } // This is a new object so add it to the local references // TODO CMPRINCE: Make this a callback or something UW.ClassroomPresenter.Network.Messages.Message.AddLocalRef(t.Id, t); return(t); } } return(s); }
/// <summary> /// Creates a new RealTimeInkSheetRenderer, which will draw ink from the specified /// <see cref="RealTimeInkSheetModel"/> on <see cref="Graphics"/> obtained /// from the specified <see cref="InkSheetRendererParent"/>. /// </summary> /// <remarks> /// By default, rendering of real-time ink is enabled. It may be disabled by setting the /// <see cref="RealTimeInkEnabled"/> property. /// <para> /// Drawing of "static" ink is always enabled, but it is only drawn when the parent /// <see cref="SlideRenderer"/> is invalidated. It is <em>not</em> drawn when new ink /// is added to the <see cref="InkSheetModel"/>, for it is assumed that a "third-party" /// <see cref="TransformableDynamicRenderer"/> or other renderer is doing the job. /// </para> /// </remarks> public RealTimeInkSheetRenderer(SlideDisplayModel display, RealTimeInkSheetModel sheet) : base(display, sheet) { this.m_Sheet = sheet; // FIXME: When the SlideViewer that created the SlideDisplayModel is invalidated, invoke TransformableDynamicRenderer.Refresh(). this.m_Renderer = new TransformableDynamicRenderer.Core.RealTimeInkAdapter(display, sheet); if((this.m_Sheet.Disposition & SheetDisposition.Remote) == 0) { this.SlideDisplay.Changed["RenderLocalRealTimeInk"].Add(new PropertyEventHandler(this.HandleRenderRealTimeInkChanged)); this.HandleRenderRealTimeInkChanged(this.SlideDisplay, null); } else { this.RenderRealTimeInk = true; } }
public RealTimeInkSheetNetworkService(SendingQueue sender, PresentationModel presentation, DeckModel deck, SlideModel slide, RealTimeInkSheetModel 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.PacketBuffers = new Dictionary<int, List<int>>(); this.PacketFlushTimes = new Dictionary<int, long>(); this.m_CurrentDrawingAttributesChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.Sender, new PropertyEventHandler(this.HandleCurrentDrawingAttributesChanged)); this.m_Sheet.Changed["CurrentDrawingAttributes"].Add(this.m_CurrentDrawingAttributesChangedDispatcher.Dispatcher); this.m_Sheet.StylusUp += new RealTimeInkSheetModel.StylusUpEventHandler(this.HandleStylusUp); this.m_Sheet.Packets += new RealTimeInkSheetModel.PacketsEventHandler(this.HandlePackets); this.m_Sheet.StylusDown += new RealTimeInkSheetModel.StylusDownEventHandler(this.HandleStylusDown); }
/// <summary> /// Create the matching between two real time ink sheets /// </summary> /// <param name="sender">The event queue to invoke async events on</param> /// <param name="srcSheet">The source sheet to marshal packets/events from</param> /// <param name="dstSheet">The destination sheet to marshal packets/events to</param> public RealTimeInkSheetMatch(EventQueue sender, RealTimeInkSheetModel srcSheet, RealTimeInkSheetModel dstSheet ) : base(sender, srcSheet, dstSheet) { // Save the parameters this.m_SourceSheet = srcSheet; this.m_DestSheet = dstSheet; // Setup event handlers for the source sheet this.m_CurrentDrawingAttributesChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.m_Sender, new PropertyEventHandler(this.HandleCurrentDrawingAttributesChanged)); this.m_SourceSheet.Changed["CurrentDrawingAttributes"].Add(this.m_CurrentDrawingAttributesChangedDispatcher.Dispatcher); this.m_SourceSheet.StylusUp += new RealTimeInkSheetModel.StylusUpEventHandler(this.HandleStylusUp); this.m_SourceSheet.Packets += new RealTimeInkSheetModel.PacketsEventHandler(this.HandlePackets); this.m_SourceSheet.StylusDown += new RealTimeInkSheetModel.StylusDownEventHandler(this.HandleStylusDown); // Setup the initial values for the Drawing Attributes this.m_Sender.Post(delegate() { this.m_CurrentDrawingAttributesChangedDispatcher.Dispatcher(this, null); }); }
/// <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; }
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; }
public RealTimeInkSheetMessage(RealTimeInkSheetModel sheet, SheetMessage.SheetCollection collection) : base(sheet, collection) { using(Synchronizer.Lock(sheet.SyncRoot)) { this.CurrentDrawingAttributes = sheet.CurrentDrawingAttributes == null ? null : new DrawingAttributesSerializer(sheet.CurrentDrawingAttributes); } }
public static Message RemoteForSheet( SheetModel sheet, SheetCollection collection) { SheetModel newModel = null; if( sheet is ImageSheetModel ) newModel = sheet; else if( sheet is RealTimeInkSheetModel ) { using( Synchronizer.Lock( sheet.SyncRoot ) ) { newModel = new RealTimeInkSheetModel( sheet.Id, sheet.Disposition | SheetDisposition.Remote, sheet.Bounds ); using( Synchronizer.Lock( newModel.SyncRoot ) ) ((RealTimeInkSheetModel)newModel).CurrentDrawingAttributes = ((RealTimeInkSheetModel)sheet).CurrentDrawingAttributes; } } else if( sheet is InkSheetModel ) newModel = sheet; else if( sheet is TextSheetModel ) newModel = sheet; else if( sheet is QuickPollSheetModel ) newModel = sheet; return SheetMessage.ForSheet( newModel, collection ); }
/// <summary> /// /// </summary> /// <param name="server"></param> /// <param name="deckIndex"></param> /// <param name="slideIndex"></param> /// <param name="strokes">SimpleWebInk objects that make up the strokes.</param> public void HandleStudentSubmission( object server, int deckIndex, int slideIndex, ArrayList strokes ) { SlideModel slide = null; DeckModel deck = null; using (Synchronizer.Lock(this.m_Presentation.SyncRoot)) { using (Synchronizer.Lock(this.m_Presentation.DeckTraversals[deckIndex].SyncRoot)) { using( Synchronizer.Lock(this.m_Presentation.DeckTraversals[deckIndex].Current.SyncRoot) ) { // Get the slide model slide = this.m_Presentation.DeckTraversals[deckIndex].Current.Slide; } deck = this.m_Presentation.DeckTraversals[deckIndex].Deck; } } // Get the student submissions deck or create it if it doesn't exist DeckModel ssDeck = this.m_Presentation.GetStudentSubmissionDeck(); if (ssDeck == null) { // Create the student submissions deck Guid ssGuid = new Guid("{78696D29-AA11-4c5b-BCF8-8E6406077FD4}"); Guid ssTraversalGuid = new Guid("{4884044B-DAE1-4249-AEF2-3A2304F52E97}"); ssDeck = new DeckModel(ssGuid, DeckDisposition.StudentSubmission, "Student Submissions"); ssDeck.Group = Group.Submissions; ssDeck.current_subs = true; // AddLocalRef(ssGuid, ssDeck); DeckTraversalModel traversal = new SlideDeckTraversalModel(ssTraversalGuid, ssDeck); // AddLocalRef(ssTraversalGuid, traversal); // Add the new student submission deck to the presentation using (Synchronizer.Lock(this.m_Presentation.SyncRoot)) { this.m_Presentation.DeckTraversals.Add(traversal); } } // Create the new slide to add SlideModel newSlide = new SlideModel( new Guid(), new LocalId(), SlideDisposition.Remote | SlideDisposition.StudentSubmission ); // Make a list of image content sheets that need to be added to the deck. List<ImageSheetModel> images = new List<ImageSheetModel>(); // Update the fields of the slide using (Synchronizer.Lock(newSlide.SyncRoot)) { using (Synchronizer.Lock(slide.SyncRoot)) { newSlide.Title = slide.Title; newSlide.Bounds = slide.Bounds; newSlide.Zoom = slide.Zoom; newSlide.BackgroundColor = slide.BackgroundColor; newSlide.BackgroundTemplate = slide.BackgroundTemplate; newSlide.SubmissionSlideGuid = slide.SubmissionSlideGuid; newSlide.SubmissionStyle = slide.SubmissionStyle; //If the slide background is null, then update the slide background with deck setting using (Synchronizer.Lock(deck.SyncRoot)) { if (slide.BackgroundColor == System.Drawing.Color.Empty) { newSlide.BackgroundColor = deck.DeckBackgroundColor; } if (slide.BackgroundTemplate == null) { newSlide.BackgroundTemplate = deck.DeckBackgroundTemplate; } } // Copy all of the content sheets. // Because ContentSheets do not change, there is no // need to do a deep copy (special case for ImageSheetModels). foreach (SheetModel s in slide.ContentSheets) { newSlide.ContentSheets.Add(s); // Queue up any image content to be added the deck below. ImageSheetModel ism = s as ImageSheetModel; if (ism != null) images.Add(ism); } // Make a deep copy of all the ink sheets foreach (SheetModel s in slide.AnnotationSheets) { SheetModel newSheet = UW.ClassroomPresenter.Model.Presentation.SheetModel.SheetDeepRemoteCopyHelper(s); newSlide.AnnotationSheets.Add(newSheet); // Queue up any image content to be added the deck below. ImageSheetModel ism = s as ImageSheetModel; if (ism != null) images.Add(ism); } } } // Add the slide content to the deck. using (Synchronizer.Lock(ssDeck.SyncRoot)) { foreach (ImageSheetModel ism in images) { System.Drawing.Image image = ism.Image; if (image == null) using (Synchronizer.Lock(ism.Deck.SyncRoot)) using (Synchronizer.Lock(ism.SyncRoot)) image = ism.Deck.GetSlideContent(ism.MD5); if (image != null) ssDeck.AddSlideContent(ism.MD5, image); } // Add the slide to the deck. ssDeck.InsertSlide(newSlide); } // Add an entry to the deck traversal so that we can navigate to the slide using (Synchronizer.Lock(ssDeck.TableOfContents.SyncRoot)) { TableOfContentsModel.Entry e = new TableOfContentsModel.Entry( new Guid(), ssDeck.TableOfContents, newSlide); ssDeck.TableOfContents.Entries.Add(e); } // Add the ink to the slide now using (Synchronizer.Lock(newSlide.SyncRoot)) { RealTimeInkSheetModel sheet = new RealTimeInkSheetModel(new Guid(), SheetDisposition.All | SheetDisposition.Remote, newSlide.Bounds); // Add the sheet newSlide.AnnotationSheets.Add(sheet); // Now add the ink using (Synchronizer.Lock(sheet.Ink.Strokes.SyncRoot)) { foreach (SimpleWebInk stroke in strokes) { Microsoft.Ink.Stroke s = sheet.Ink.CreateStroke(stroke.Pts); s.DrawingAttributes.Color = System.Drawing.Color.FromArgb(stroke.R, stroke.G, stroke.B); s.DrawingAttributes.RasterOperation = (stroke.Opacity < 255) ? Microsoft.Ink.RasterOperation.MaskPen : Microsoft.Ink.RasterOperation.CopyPen; s.DrawingAttributes.Width = stroke.Width * 30.00f; } } } }
protected override bool UpdateTarget(ReceiveContext context) { RealTimeInkSheetModel sheet = this.Target as RealTimeInkSheetModel; if(sheet == null) { this.Target = sheet = new RealTimeInkSheetModel(((Guid) this.TargetId), this.Disposition | SheetDisposition.Remote, this.Bounds); using(Synchronizer.Lock(sheet.SyncRoot)) { if(this.CurrentDrawingAttributes != null) sheet.CurrentDrawingAttributes = this.CurrentDrawingAttributes.CreateDrawingAttributes(); } } else { using(Synchronizer.Lock(sheet.SyncRoot)) { if(this.CurrentDrawingAttributes != null) { DrawingAttributes changed = sheet.CurrentDrawingAttributes; if(changed == null || this.CurrentDrawingAttributes.NeedsUpdate(changed)) { changed = this.CurrentDrawingAttributes.CreateDrawingAttributes(); sheet.CurrentDrawingAttributes = changed; } } else { sheet.CurrentDrawingAttributes = null; } } } base.UpdateTarget(context); return true; }
/// <summary> /// Constructs a new <see cref="RealTimeInkAdapater"/> instance, which will render ink /// generated received from the <see cref="RealTimeInkSheetModel"/> onto the graphics device /// specified by the <see cref="SlideDisplayModel"/> /// </summary> public RealTimeInkAdapter(SlideDisplayModel display, RealTimeInkSheetModel rti) : base(display) { this.m_RTI = rti; this.m_CurrentDrawingAttributesChangedDispatcher = new EventQueue.PropertyEventDispatcher(this.m_SlideDisplay.EventQueue, new PropertyEventHandler(this.HandleCurrentDrawingAttributesChanged)); this.m_RTI.Changed["CurrentDrawingAttributes"].Add(this.m_CurrentDrawingAttributesChangedDispatcher.Dispatcher); this.m_RTI.StylusDown += new RealTimeInkSheetModel.StylusDownEventHandler(this.HandleStylusDown); this.m_RTI.StylusUp += new RealTimeInkSheetModel.StylusUpEventHandler(this.HandleStylusUp); this.m_RTI.Packets += new RealTimeInkSheetModel.PacketsEventHandler(this.HandlePackets); this.m_CurrentDrawingAttributesChangedDispatcher.Dispatcher(this.m_RTI, null); }
public RealTimeInkSheetInformationMessage(RealTimeInkSheetModel sheet, SheetMessage.SheetCollection collection) : base(sheet, collection) { }
protected Guid SendStudentSubmission( Guid TOCEntryGuid ) { Guid newSlideGuid = Guid.Empty; UW.ClassroomPresenter.Network.Messages.Message pres, deck, slide, sheet; // Add the presentation if( this.m_Presentation == null ) return Guid.Empty; pres = new PresentationInformationMessage( this.m_Presentation ); pres.Group = Groups.Group.Submissions; //Add the current deck model that corresponds to this slide deck at the remote location deck = new DeckInformationMessage( this.m_Deck ); deck.Group = Groups.Group.Submissions; pres.InsertChild( deck ); // Add the Slide Message newSlideGuid = Guid.NewGuid(); TOCEntryGuid = Guid.NewGuid(); slide = new StudentSubmissionSlideInformationMessage( this.m_Slide, newSlideGuid, TOCEntryGuid ); slide.Group = Groups.Group.Submissions; deck.InsertChild( slide ); // Find the correct user ink layer to send RealTimeInkSheetModel m_Sheet = null; using( Synchronizer.Lock( this.m_Slide.SyncRoot ) ) { foreach( SheetModel s in this.m_Slide.AnnotationSheets ) { if( s is RealTimeInkSheetModel && (s.Disposition & SheetDisposition.Remote) == 0 ) { m_Sheet = (RealTimeInkSheetModel)s; break; } } } // Find the existing ink on the slide Microsoft.Ink.Ink extracted; using( Synchronizer.Lock( m_Sheet.Ink.Strokes.SyncRoot ) ) { // Ensure that each stroke has a Guid which will uniquely identify it on the remote side foreach( Microsoft.Ink.Stroke stroke in m_Sheet.Ink.Strokes ) { if( !stroke.ExtendedProperties.DoesPropertyExist( InkSheetMessage.StrokeIdExtendedProperty ) ) stroke.ExtendedProperties.Add( InkSheetMessage.StrokeIdExtendedProperty, Guid.NewGuid().ToString() ); } // Extract all of the strokes extracted = m_Sheet.Ink.ExtractStrokes( m_Sheet.Ink.Strokes, Microsoft.Ink.ExtractFlags.CopyFromOriginal ); } // Find the Realtime ink on the slide RealTimeInkSheetModel newSheet = null; using( Synchronizer.Lock( m_Sheet.SyncRoot ) ) { newSheet = new RealTimeInkSheetModel( Guid.NewGuid(), m_Sheet.Disposition | SheetDisposition.Remote, m_Sheet.Bounds ); using( Synchronizer.Lock( newSheet.SyncRoot ) ) { newSheet.CurrentDrawingAttributes = m_Sheet.CurrentDrawingAttributes; } } // Add the Sheet Message for the existing ink sheet = new InkSheetStrokesAddedMessage(newSheet, (Guid)slide.TargetId, SheetMessage.SheetCollection.AnnotationSheets, extracted); sheet.Group = Groups.Group.Submissions; slide.InsertChild( sheet ); // Add the Sheet Message for the real-time ink sheet = SheetMessage.ForSheet( newSheet, SheetMessage.SheetCollection.AnnotationSheets ); sheet.Group = Groups.Group.Submissions; slide.AddOldestPredecessor( sheet ); // Send the message this.m_Sender.Send( pres ); return newSlideGuid; }
/// <summary> /// Send the current ink as a student submission slide /// </summary> /// <param name="sender">The object which sent this event, i.e. this class</param> /// <param name="args">The parameters for the property</param> private void HandleSendSubmission( object sender, PropertyEventArgs args ) { if (this.m_SendingLock) return; using (Synchronizer.Lock(SubmissionStatusModel.GetInstance().SyncRoot)) { SubmissionStatusModel.GetInstance().SubmissionStatus = SubmissionStatusModel.Status.NotReceived; } ///declare variables we will be using UW.ClassroomPresenter.Network.Messages.Message pres, deck, slide, sheet; // Construct the message to send using( this.m_Model.Workspace.Lock() ) { // Add the presentation if( this.m_Model.Workspace.CurrentPresentation == null ) return; ///the presentation message we will be sending pres = new PresentationInformationMessage( this.m_Model.Workspace.CurrentPresentation ); pres.Group = Groups.Group.Submissions; //Add the current deck model that corresponds to this slide deck at the remote location if( (~this.m_Model.Workspace.CurrentDeckTraversal) == null ) return; using( Synchronizer.Lock( (~this.m_Model.Workspace.CurrentDeckTraversal).SyncRoot ) ) { DeckModel dModel = (~this.m_Model.Workspace.CurrentDeckTraversal).Deck; foreach( DeckPairModel match in this.m_Model.Workspace.DeckMatches ) { ///check to see if the decks are the same if( match.LocalDeckTraversal.Deck == (~this.m_Model.Workspace.CurrentDeckTraversal).Deck ) dModel = match.RemoteDeckTraversal.Deck; } ///create the deck message from this matched deck deck = new DeckInformationMessage( dModel ); ///make the deck a submission type deck. deck.Group = Groups.Group.Submissions; ///tack this message onto the end. pres.InsertChild( deck ); ///add the particular slide we're on the to message. if( (~this.m_Model.Workspace.CurrentDeckTraversal).Current == null ) return; using( Synchronizer.Lock( (~this.m_Model.Workspace.CurrentDeckTraversal).Current.Slide.SyncRoot ) ) { // Add the Slide Message slide = new StudentSubmissionSlideInformationMessage( (~this.m_Model.Workspace.CurrentDeckTraversal).Current.Slide, Guid.NewGuid(), Guid.NewGuid() ); slide.Group = Groups.Group.Submissions; deck.InsertChild( slide ); // Find the correct user ink layer to send RealTimeInkSheetModel m_Sheet = null; int count = 0; foreach( SheetModel s in (~this.m_Model.Workspace.CurrentDeckTraversal).Current.Slide.AnnotationSheets ) { if( s is RealTimeInkSheetModel && (s.Disposition & SheetDisposition.Remote) == 0 ) { m_Sheet = (RealTimeInkSheetModel)s; count++; } } // DEBUGGING if( count > 1 ) Debug.Assert( true, "Bad Count", "Bad" ); // Find the existing ink on the slide Ink extracted; using( Synchronizer.Lock( m_Sheet.Ink.Strokes.SyncRoot ) ) { // Ensure that each stroke has a Guid which will uniquely identify it on the remote side foreach( Stroke stroke in m_Sheet.Ink.Strokes ) { if( !stroke.ExtendedProperties.DoesPropertyExist( InkSheetMessage.StrokeIdExtendedProperty ) ) stroke.ExtendedProperties.Add( InkSheetMessage.StrokeIdExtendedProperty, Guid.NewGuid().ToString() ); } // Extract all of the strokes extracted = m_Sheet.Ink.ExtractStrokes( m_Sheet.Ink.Strokes, ExtractFlags.CopyFromOriginal ); } // Find the Realtime ink on the slide RealTimeInkSheetModel newSheet = null; using( Synchronizer.Lock( m_Sheet.SyncRoot ) ) { newSheet = new RealTimeInkSheetModel( Guid.NewGuid(), m_Sheet.Disposition | SheetDisposition.Remote, m_Sheet.Bounds ); using( Synchronizer.Lock( newSheet.SyncRoot ) ) { newSheet.CurrentDrawingAttributes = m_Sheet.CurrentDrawingAttributes; } } // Add a message to *create* the student's RealTimeInkSheetModel on the instructor client (without any ink). sheet = SheetMessage.ForSheet(newSheet, SheetMessage.SheetCollection.AnnotationSheets); sheet.Group = Groups.Group.Submissions; slide.InsertChild(sheet); //Scale the ink if necessary if (ViewerStateModel.NonStandardDpi) { extracted.Strokes.Transform(ViewerStateModel.DpiNormalizationSendMatrix); } // Add a message to copy the ink from the student's RealTimeInkSheetModel to the just-created sheet on the instructor. sheet = new InkSheetStrokesAddedMessage(newSheet, (Guid)slide.TargetId, SheetMessage.SheetCollection.AnnotationSheets, extracted); sheet.Group = Groups.Group.Submissions; slide.InsertChild( sheet ); ///Add each text and image sheet into the message as children of the ink sheet if it is public foreach( SheetModel s in (~this.m_Model.Workspace.CurrentDeckTraversal).Current.Slide.AnnotationSheets ) { if( s is TextSheetModel && !(s is StatusLabel) && (s.Disposition & SheetDisposition.Remote) == 0) { TextSheetModel text_sheet = (TextSheetModel) s; text_sheet = (TextSheetModel) text_sheet.Clone(); ///some ugly code here due to synchronization bool sheet_is_public; using (Synchronizer.Lock(text_sheet.SyncRoot)) { sheet_is_public = text_sheet.IsPublic; } if (sheet_is_public) { TextSheetMessage t_message = new TextSheetMessage(text_sheet, SheetMessage.SheetCollection.AnnotationSheets); t_message.Group = Groups.Group.Submissions; slide.InsertChild(t_message); } } if (s is ImageSheetModel && !(s is StatusLabel) && (s.Disposition & SheetDisposition.Remote) == 0) { ImageSheetModel image_sheet = (ImageSheetModel)s; image_sheet = (ImageSheetModel) image_sheet.Clone(); ImageSheetMessage i_message = new ImageSheetMessage(image_sheet, SheetMessage.SheetCollection.AnnotationSheets); i_message.Group = Groups.Group.Submissions; slide.InsertChild(i_message); } } //Lock the current sending. this.LockSending(); // Send the message this.m_Sender.Send(pres); } } } }
public RealTimeInkSheetStylusUpMessage(RealTimeInkSheetModel sheet, int stylusId, int strokeId, int[] packets) : base(sheet, stylusId, strokeId, packets) { }
public RealTimeInkSheetStylusDownMessage(RealTimeInkSheetModel sheet, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties) : base(sheet, stylusId, strokeId, packets) { this.TabletProperties = new TabletPropertyDescriptionCollectionInformation(tabletProperties); }
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; } } } } }
/// <summary> /// Performs a deep copy of the given SheetModel. /// If the given sheetmodel is an InkSheet or an editable sheet, it is copied, otherwise, it returns itself. /// </summary> /// <param name="s">The SheetModel to copy</param> /// <returns>A deep copy of an InkSheet or an Editable Sheet, otherwise, itself</returns> public static SheetModel SheetDeepCopyHelper(SheetModel s) { using (Synchronizer.Lock(s.SyncRoot)) { SheetModel t = null; // Only copy InkSheetModels if (s is InkSheetModel || s is EditableSheetModel) { if (s is RealTimeInkSheetModel) { // Make a deep copy of the SheetModel // t = new RealTimeInkSheetModel(Guid.NewGuid(), SheetDisposition.All, s.Bounds, ((RealTimeInkSheetModel)s).Ink.Clone()); t = new RealTimeInkSheetModel(Guid.NewGuid(), s.Disposition, s.Bounds, ((RealTimeInkSheetModel)s).Ink.Clone()); using (Synchronizer.Lock(t.SyncRoot)) { ((RealTimeInkSheetModel)t).CurrentDrawingAttributes = ((RealTimeInkSheetModel)s).CurrentDrawingAttributes; } } else if (s is InkSheetModel) { // Make a deep copy of the SheetModel t = new InkSheetModel(Guid.NewGuid(), s.Disposition, s.Bounds, ((InkSheetModel)s).Ink.Clone()); } else if (s is EditableSheetModel) { t = (EditableSheetModel)((EditableSheetModel)s).Clone(); } // This is a new object so add it to the local references // TODO CMPRINCE: Make this a callback or something UW.ClassroomPresenter.Network.Messages.Message.AddLocalRef(t.Id, t); return t; } } return s; }