private void HandleInkAddedHelper(Ink extracted) { Message message, deck, slide, sheet; message = new PresentationInformationMessage(this.Presentation); message.InsertChild(deck = new DeckInformationMessage(this.Deck)); deck.InsertChild(slide = new SlideInformationMessage(GetSubmissionSlideModel(), false)); slide.InsertChild(sheet = new InkSheetStrokesAddedMessage(this.m_Sheet, (Guid)slide.TargetId, this.SheetCollectionSelector, extracted)); sheet.AddOldestPredecessor(SheetMessage.RemoteForSheet(this.m_Sheet, this.SheetCollectionSelector)); this.Sender.Send(message); }
protected override MergeAction MergeInto(Message other_) { if (other_ is InkSheetStrokesAddedMessage) { InkSheetStrokesAddedMessage other = ((InkSheetStrokesAddedMessage)other_); byte[][] merged = new byte[other.SavedInks.Length + this.SavedInks.Length][]; other.SavedInks.CopyTo(merged, 0); this.SavedInks.CopyTo(merged, other.SavedInks.Length); other.SavedInks = merged; return(MergeAction.DiscardThis); } return(base.MergeInto(other_)); }
private void HandleInkAddedHelper(Ink extracted, Group receivers) { if (ViewerStateModel.NonStandardDpi) { extracted.Strokes.Transform(ViewerStateModel.DpiNormalizationSendMatrix, true); } try { Message message = new InkSheetStrokesAddedMessage(this.m_Sheet, m_SlideID, this.SheetCollectionSelector, extracted); message.Group = receivers; message.Tags = new MessageTags(); message.Tags.SlideID = m_SlideID; message.Tags.BridgePriority = MessagePriority.Higher; this.Sender.Send(message); } catch (OutOfMemoryException e) { Trace.WriteLine(e.ToString()); GC.Collect(); } }
private void HandleInkAddedHelper(Ink extracted, Group receivers) { if (ViewerStateModel.NonStandardDpi) { extracted.Strokes.Transform(ViewerStateModel.DpiNormalizationSendMatrix, true); } try { Message message = new InkSheetStrokesAddedMessage(this.m_Sheet, m_SlideID, this.SheetCollectionSelector, extracted); message.Group = receivers; message.Tags = new MessageTags(); message.Tags.SlideID = m_SlideID; message.Tags.BridgePriority = MessagePriority.Higher; this.Sender.Send(message); } catch (OutOfMemoryException e) { Trace.WriteLine(e.ToString()); GC.Collect(); } }
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; }
protected Guid SendStudentSubmission() { Guid newSlideGuid = Guid.Empty; UW.ClassroomPresenter.Network.Messages.Message pres, deck, slide, sheet; // Add the presentation if (this.Presentation == null) { return(Guid.Empty); } pres = new PresentationInformationMessage(this.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.Deck); deck.Group = Groups.Group.Submissions; pres.InsertChild(deck); // Add the Slide Message newSlideGuid = Guid.NewGuid(); slide = new StudentSubmissionSlideInformationMessage(this.Slide, newSlideGuid, Guid.NewGuid()); slide.Group = Groups.Group.Submissions; deck.InsertChild(slide); // Find the correct user ink layer to send RealTimeInkSheetModel m_Sheet = null; using (Synchronizer.Lock(this.Slide.SyncRoot)) { foreach (SheetModel s in this.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 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); }
private void HandleInkAddedHelper(Ink extracted) { Message message, deck, slide, sheet; message = new PresentationInformationMessage(this.Presentation); message.InsertChild(deck = new DeckInformationMessage(this.Deck)); deck.InsertChild(slide = new SlideInformationMessage( GetSubmissionSlideModel(), false )); slide.InsertChild(sheet = new InkSheetStrokesAddedMessage(this.m_Sheet, (Guid)slide.TargetId, this.SheetCollectionSelector, extracted)); sheet.AddOldestPredecessor( SheetMessage.RemoteForSheet( this.m_Sheet, this.SheetCollectionSelector ) ); this.Sender.Send(message); }
/// <summary> /// This is the message received when there is a completed stroke. Translate to RTDrawStroke. /// </summary> /// <param name="issam"></param> /// <returns></returns> internal RTDrawStroke AddInkSheetStrokesAdded(CP3Msgs.InkSheetStrokesAddedMessage issam) { //Notice that we tend to get a fair number of these messages that have nothing in the SavedInks property.. presenter bug? byte[][] saved = issam.SavedInks; if (saved.Length == 0) { return(null); } if (saved[0].Length == 0) { return(null); } if (saved.Length > 1) { //This does not seem to occur in practice. If it ever does, we need to generate multiple RTDrawStroke messages: warning += "Warning: Valid ink may be ignored because we only support one byte[] per ink message. "; } Ink ink = new Ink(); ink.Load(saved[0]); if (ink.Strokes.Count <= 0) { return(null); } //This message has a targetID identifying a Sheet which we use to look up a toc entry. Debug.WriteLine("***** InkSheetStrokesAdded targetid=" + issam.TargetId.ToString()); if (!sheetToSlideLookup.ContainsKey(issam.TargetId)) { if (issam.SlideId.Equals(Guid.Empty)) { //Don't think this should ever happen. warning += "Warning: InkSheetStrokesAdded does not match a known sheet. Ignoring ink. "; return(null); } sheetToSlideLookup.Add(issam.TargetId, issam.SlideId); } Guid slideId = (Guid)sheetToSlideLookup[issam.TargetId]; //Get DeckID and Slide index from toc. Return RTDrawStroke. TableOfContents.TocEntry tocEntry = toc.LookupBySlideId(slideId); if (tocEntry == null) { //In some cases ink arrives before the TOC entry. // Save the ink to send later when the TOC entry is available. if (!pendingInk.ContainsKey(slideId)) { pendingInk.Add(slideId, new List <Ink>()); } pendingInk[slideId].Add(ink); Debug.WriteLine("InkSheetStrokesAdded does not have a Toc entry. Caching for later."); return(null); } Guid strokeId = Guid.NewGuid(); //Pull out the identifier which is used if we need to delete the stroke later: if (ink.Strokes[0].ExtendedProperties.DoesPropertyExist(StrokeIdExtendedProperty)) { strokeId = new Guid((string)ink.Strokes[0].ExtendedProperties[StrokeIdExtendedProperty].Data); } else { warning += "Warning: Failed to find stroke Id. "; } //WebViewer looks for the CP2 extended property, so add it too. ink.Strokes[0].ExtendedProperties.Add(CP2StrokeIdExtendedProperty, (object)strokeId.ToString()); //WebViewer wants ink to be scaled to 500x500 ink.Strokes.Scale(500f / getCurrentSlideWidth(), 500f / getCurrentSlideHeight()); //Debug.WriteLine("***** Adding Stroke ID=" + strokeId.ToString()); RTDrawStroke rtds = new RTDrawStroke(ink, strokeId, true, tocEntry.DeckId, tocEntry.SlideIndex); //Add the stroke to our list to optimize deletes if (!strokeCountsBySlideId.ContainsKey(slideId)) { strokeCountsBySlideId.Add(slideId, 1); } else { strokeCountsBySlideId[slideId]++; } return(rtds); }
/// <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); } } } }