//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Add an annotation to the map /// throws an exception if the annotation already exists /// </summary> /// <param name="annotation">instance of annotation to add to the map</param> /// <param name="dirty">the initial dirty flag of the annotation in the map</param> public void AddAnnotation(Annotation annotation, bool dirty) { Debug.Assert(FindAnnotation(annotation.Id) == null, "annotation not found"); annotation.AuthorChanged += OnAuthorChanged; annotation.AnchorChanged += OnAnchorChanged; annotation.CargoChanged += OnCargoChanged; _currentAnnotations.Add(annotation.Id, new CachedAnnotation(annotation, dirty)); }
/// <summary> /// Create an instance of AttachedAnnotation with a specified parent. Takes an optional /// parent for the attached annotation. This is useful when the parent is known before /// hand and not available through the normal means (such as in printing). /// </summary> /// <param name="manager">the LocatorManager providing processors for this anchored annotation</param> /// <param name="annotation">the annotation itself</param> /// <param name="anchor">the annotation's anchor represented by the attached anchor</param> /// <param name="attachedAnchor">the attached anchor itself</param> /// <param name="attachmentLevel">the level of the attached anchor</param> /// <param name="parent">parent of the selection</param> internal AttachedAnnotation(LocatorManager manager, Annotation annotation, AnnotationResource anchor, Object attachedAnchor, AttachmentLevel attachmentLevel, DependencyObject parent) { Debug.Assert(manager != null, "LocatorManager can not be null"); Debug.Assert(annotation != null, "Annotation can not be null"); Debug.Assert(anchor != null, "Anchor can not be null"); Debug.Assert(attachedAnchor != null, "AttachedAnchor can not be null"); _annotation = annotation; _anchor = anchor; _locatorManager = manager; Update(attachedAnchor, attachmentLevel, parent); }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors /// <summary> /// Creates an instance of AuthorChangedEventArgs. /// </summary> /// <param name="annotation">the Annotation firing the event</param> /// <param name="action">the action taken on the Author</param> /// <param name="author">the Author that was changed</param> /// <exception cref="ArgumentNullException">annotation is null</exception> /// <exception cref="InvalidEnumArgumentException">action is not a valid value from AnnotationAction</exception> public AnnotationAuthorChangedEventArgs(Annotation annotation, AnnotationAction action, Object author) { // The author parameter can be null here - it is possible to add a null to // the list of authors and we must fire an event signalling a change in the collection. if (annotation == null) { throw new ArgumentNullException("annotation"); } if (action < AnnotationAction.Added || action > AnnotationAction.Modified) { throw new InvalidEnumArgumentException("action", (int)action, typeof(AnnotationAction)); } _annotation = annotation; _author = author; _action = action; }
//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Add a new annotation to this store. The new annotation's Id /// is set to a new value. /// </summary> /// <param name="newAnnotation">the annotation to be added to the store</param> /// <exception cref="ArgumentNullException">newAnnotation is null</exception> /// <exception cref="ArgumentException">newAnnotation already exists in this store, as determined by its Id</exception> /// <exception cref="ObjectDisposedException">if object has been disposed</exception> public abstract void AddAnnotation(Annotation newAnnotation);
/// <summary> /// Creates an annotation of the specified type in the service. The current /// selection of the DocumentViewerBase is used as the anchor of the new /// annotation. /// If the selection is of length 0 no annotation is created. /// If the no locators can be generated for the textAnchor, no annotation is created. /// </summary> /// <param name="service">the AnnotationService</param> /// <param name="textSelection">text selection for new annotation</param> /// <param name="annotationType">the type of the annotation to create</param> /// <param name="author">optional author for new annotation</param> /// <returns>the annotation created</returns> /// <exception cref="ArgumentException">service is not enabled</exception> /// <exception cref="InvalidOperationException">selection is of zero length</exception> private static Annotation CreateAnnotationForSelection(AnnotationService service, ITextRange textSelection, XmlQualifiedName annotationType, string author) { Invariant.Assert(service != null && textSelection != null, "Parameter 'service' or 'textSelection' is null."); // Limited set of annotation types supported in V1 Invariant.Assert(annotationType != null && (annotationType == HighlightComponent.TypeName || annotationType == StickyNoteControl.TextSchemaName || annotationType == StickyNoteControl.InkSchemaName), "Invalid Annotation Type"); Annotation annotation = new Annotation(annotationType); SetAnchor(service, annotation, textSelection); // Add the author to the annotation if (author != null) { annotation.Authors.Add(author); } return annotation; }
/// <summary> /// Gets the AttachedAnnotation for any annotation, even if its not visible. /// </summary> /// <param name="service">service from which to resolve annotations</param> /// <param name="annotation">annotation to get anchor info for</param> /// <exception cref="ArgumentNullException">service or annotation is null</exception> /// <exception cref="ArgumentException">service is not enabled</exception> public static IAnchorInfo GetAnchorInfo(AnnotationService service, Annotation annotation) { CheckInputs(service); if (annotation == null) throw new ArgumentNullException("annotation"); bool isFlow = true; // Determine if we are using a viewer that supports pagination DocumentViewerBase viewer = service.Root as DocumentViewerBase; if (viewer == null) { FlowDocumentReader fdr = service.Root as FlowDocumentReader; if (fdr != null) { viewer = GetFdrHost(fdr) as DocumentViewerBase; } } else { // Only paginated viewers support non-FlowDocuments, so // if we have one, check its content type isFlow = viewer.Document is FlowDocument; } IList<IAttachedAnnotation> attachedAnnotations = null; // Use the method specific to the kind of content we are displaying if (isFlow) { TextSelectionProcessor rangeProcessor = service.LocatorManager.GetSelectionProcessor(typeof(TextRange)) as TextSelectionProcessor; TextSelectionProcessor anchorProcessor = service.LocatorManager.GetSelectionProcessor(typeof(TextAnchor)) as TextSelectionProcessor; Invariant.Assert(rangeProcessor != null, "TextSelectionProcessor should be available for TextRange if we are processing flow content."); Invariant.Assert(anchorProcessor != null, "TextSelectionProcessor should be available for TextAnchor if we are processing flow content."); try { // Turn resolving for non-visible content on rangeProcessor.Clamping = false; anchorProcessor.Clamping = false; attachedAnnotations = ResolveAnnotations(service, new Annotation[] { annotation }); } finally { // Turn resolving of non-visible content off again rangeProcessor.Clamping = true; anchorProcessor.Clamping = true; } } else { FixedPageProcessor processor = service.LocatorManager.GetSubTreeProcessorForLocatorPart(FixedPageProcessor.CreateLocatorPart(0)) as FixedPageProcessor; Invariant.Assert(processor != null, "FixedPageProcessor should be available if we are processing fixed content."); try { // Turn resolving of non-visible anchors on processor.UseLogicalTree = true; attachedAnnotations = ResolveAnnotations(service, new Annotation[] { annotation }); } finally { // Turn resolving of non-visible anchors off again processor.UseLogicalTree = false; } } Invariant.Assert(attachedAnnotations != null); if (attachedAnnotations.Count > 0) return attachedAnnotations[0]; return null; }
private static void SetAnchor(AnnotationService service, Annotation annot, object selection) { Invariant.Assert(annot != null && selection != null, "null input parameter"); // Generate locators for the selection - add them to the anchor IList<ContentLocatorBase> locators = service.LocatorManager.GenerateLocators(selection); Invariant.Assert(locators != null && locators.Count > 0, "No locators generated for selection."); // Create an annotation with a single anchor AnnotationResource anchor = new AnnotationResource(); // Add the locators to the anchor foreach (ContentLocatorBase locator in locators) { anchor.ContentLocators.Add(locator); } annot.Anchors.Clear(); annot.Anchors.Add(anchor); }
public SNCAnnotation(Annotation annotation) { Debug.Assert(annotation != null); _annotation = annotation; _isNewAnnotation = _annotation.Cargos.Count == 0; // Initialize the data cache collection. _cachedXmlElements = new Dictionary<XmlToken, object>(); }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors /// <summary> /// Create an instance of AttachedAnnotation. /// </summary> /// <param name="manager">the LocatorManager providing processors for this anchored annotation</param> /// <param name="annotation">the annotation itself</param> /// <param name="anchor">the annotation's anchor represented by the attached anchor</param> /// <param name="attachedAnchor">the attached anchor itself</param> /// <param name="attachmentLevel">the level of the attached anchor</param> internal AttachedAnnotation(LocatorManager manager, Annotation annotation, AnnotationResource anchor, Object attachedAnchor, AttachmentLevel attachmentLevel) : this(manager, annotation, anchor, attachedAnchor, attachmentLevel, null) { }
/// <summary> /// handle the case when a new anchor is added to the annotation /// </summary> /// <param name="annotation">the annotation which anchor was affected</param> /// <param name="anchor">the deleted anchor</param> /// <returns></returns> private AttachedAnnotationChangedEventArgs AnchorAdded(Annotation annotation, AnnotationResource anchor) { Invariant.Assert(annotation != null && anchor != null, "Parameter 'annotation' or 'anchor' is null."); AttachedAnnotationChangedEventArgs args = null; AttachmentLevel attachmentLevel; object attachedAnchor = FindAttachedAnchor(anchor, out attachmentLevel); if (attachmentLevel != AttachmentLevel.Unresolved && attachmentLevel != AttachmentLevel.Incomplete) { Invariant.Assert(attachedAnchor != null, "Must have a valid attached anchor."); AttachedAnnotation attachedAnnotation = new AttachedAnnotation( this.LocatorManager, annotation, anchor, attachedAnchor, attachmentLevel); DoAddAttachedAnnotation(attachedAnnotation); args = AttachedAnnotationChangedEventArgs.Added(attachedAnnotation); } return args; }
/// <summary> /// a handler for the storeupdate annotation added action /// </summary> /// <param name="annotation">the annotation added to the store</param> private void AnnotationAdded(Annotation annotation) { Invariant.Assert(annotation != null, "Parameter 'annotation' is null."); // if we already have an annotation in our map - then something is messed up (store has bug) // we are getting an add event on something that already exists - throw an exception if (_annotationMap.GetAttachedAnnotations(annotation.Id).Count > 0) throw new Exception(SR.Get(SRID.AnnotationAlreadyExistInService)); List<AttachedAnnotationChangedEventArgs> eventsToFire = new List<AttachedAnnotationChangedEventArgs>(annotation.Anchors.Count); foreach (AnnotationResource anchor in annotation.Anchors) { if (anchor.ContentLocators.Count == 0) continue; // attachedAnchor without locator, keep looping AttachedAnnotationChangedEventArgs args = AnchorAdded(annotation, anchor); if (args != null) { eventsToFire.Add(args); } } FireEvents(eventsToFire); }
//------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods /// <summary> /// Add a new annotation to this store. The new annotation's Id /// is set to a new value. /// </summary> /// <param name="newAnnotation">the annotation to be added to the store</param> /// <exception cref="ArgumentNullException">newAnnotation is null</exception> /// <exception cref="ArgumentException">newAnnotation already exists in this store, as determined by its Id</exception> /// <exception cref="InvalidOperationException">if no stream has been set on the store</exception> /// <exception cref="ObjectDisposedException">if object has been Disposed</exception> public override void AddAnnotation(Annotation newAnnotation) { if (newAnnotation == null) throw new ArgumentNullException("newAnnotation"); // We are going to modify internal data. Lock the object // to avoid modifications from other threads lock (SyncRoot) { //fire trace event EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.AddAnnotationBegin); try { CheckStatus(); XPathNavigator editor = GetAnnotationNodeForId(newAnnotation.Id); // we are making sure that the newAnnotation doesn't already exist in the store if (editor != null) throw new ArgumentException(SR.Get(SRID.AnnotationAlreadyExists), "newAnnotation"); // we are making sure that the newAnnotation doesn't already exist in the store map if (_storeAnnotationsMap.FindAnnotation(newAnnotation.Id) != null) throw new ArgumentException(SR.Get(SRID.AnnotationAlreadyExists), "newAnnotation"); // simply add the annotation to the map to save on performance // notice that we need to tell the map that this instance of the annotation is dirty _storeAnnotationsMap.AddAnnotation(newAnnotation, true); } finally { //fire trace event EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.AddAnnotationEnd); } } OnStoreContentChanged(new StoreContentChangedEventArgs(StoreContentAction.Added, newAnnotation)); }
/// <summary> /// Gets the Colors from the Annotation's cargo. If corresponding Color is not present /// a default value is used. /// </summary> /// <param name="annot">The Annotation</param> /// <param name="backgroundColor">background Color</param> /// <param name="activeBackgroundColor">background Color for active highlight</param> private void GetColors(Annotation annot, out Color backgroundColor, out Color activeBackgroundColor) { Nullable<Color> tempBackgroundColor = _defaultBackroundColor; Nullable<Color> tempActiveBackgroundColor = _defaultActiveBackgroundColor; GetCargoColors(annot, ref tempBackgroundColor, ref tempActiveBackgroundColor); backgroundColor = (Color)tempBackgroundColor; activeBackgroundColor = (Color)tempActiveBackgroundColor; }
/// <summary> /// Looks for Colors from the Annotation's cargo. If corresponding Color is present /// set it to the input parameter. Otherwise leave the parameter intact. /// </summary> /// <param name="annot">The Annotation</param> /// <param name="backgroundColor">background Color</param> /// <param name="activeBackgroundColor">background Color for active highlight</param> internal static void GetCargoColors(Annotation annot, ref Nullable<Color> backgroundColor, ref Nullable<Color> activeBackgroundColor) { Invariant.Assert(annot != null, "annotation is null"); ICollection<AnnotationResource> cargos = annot.Cargos; if (cargos != null) { foreach (AnnotationResource cargo in cargos) { if (cargo.Name == HighlightResourceName) { ICollection contents = cargo.Contents; foreach (XmlElement content in contents) { if ((content.LocalName == ColorsContentName) && (content.NamespaceURI == AnnotationXmlConstants.Namespaces.BaseSchemaNamespace)) { if (content.Attributes[BackgroundAttributeName] != null) backgroundColor = GetColor(content.Attributes[BackgroundAttributeName].Value); if (content.Attributes[ActiveBackgroundAttributeName] != null) activeBackgroundColor = GetColor(content.Attributes[ActiveBackgroundAttributeName].Value); } } } } } }
public AnnotationAuthorChangedEventArgs(Annotation annotation, AnnotationAction action, Object author) { }
/// <summary> /// Construct a CachedAnnotation /// </summary> /// <param name="annotation">The annotation instance to be cached</param> /// <param name="dirty">A flag to indicate if the annotation is dirty</param> public CachedAnnotation(Annotation annotation, bool dirty) { Annotation = annotation; Dirty = dirty; }
/// <summary> /// handle the case when an anchor is removed from the annotation /// </summary> /// <param name="annotation">the annotation which anchor was affected</param> /// <param name="anchor">the removed anchor</param> /// <returns>EventArgs to use when firing an AttachedAnnotationChanged event</returns> private AttachedAnnotationChangedEventArgs AnchorRemoved(Annotation annotation, AnnotationResource anchor) { Invariant.Assert(annotation != null && anchor != null, "Parameter 'annotation' or 'anchor' is null."); AttachedAnnotationChangedEventArgs args = null; IList<IAttachedAnnotation> annotations = _annotationMap.GetAttachedAnnotations(annotation.Id); if (annotations.Count > 0) { // Since we will be modifying this collection, we make a copy of it to iterate on IAttachedAnnotation[] list = new IAttachedAnnotation[annotations.Count]; annotations.CopyTo(list, 0); foreach (IAttachedAnnotation attachedAnnotation in list) { if (attachedAnnotation.Anchor == anchor) { DoRemoveAttachedAnnotation(attachedAnnotation); args = AttachedAnnotationChangedEventArgs.Deleted(attachedAnnotation); break; } } } return args; }
// ----------------------- AddBookmarkOrComment ----------------------- private void AddBookmarkOrComment(ListBox collection, Annotation ann) { if (ann.Cargos.Count <= 1) { ann.Cargos.Add( new AnnotationResource( FDPV.MasterPageNumber.ToString() ) ); } Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); string path = System.IO.Path.Combine( a.Location.Remove(a.Location.LastIndexOf('\\')), "GoButton.xaml"); StackPanel EntryInList = XamlReader.Load(File.OpenRead(path)) as StackPanel; EntryInList.Width = BookmarkList.Width - 10; Button GoToMark = LogicalTreeHelper.FindLogicalNode( EntryInList, "GoToMark") as Button; if (GoToMark != null) { GoToMark.Tag = ann; GoToMark.Click += new RoutedEventHandler(GoToMark_Click); } MenuItem GoToMenu = LogicalTreeHelper.FindLogicalNode( GoToMark.ContextMenu, "GoToMenu") as MenuItem; GoToMenu.Click += new RoutedEventHandler(GoToMark_Click); GoToMenu.Tag = ann; MenuItem DeleteMark = LogicalTreeHelper.FindLogicalNode( GoToMark.ContextMenu, "DeleteMark") as MenuItem; DeleteMark.Click += new RoutedEventHandler(DeleteMark_Click); DeleteMark.Tag = ann; System.Windows.Shapes.Path markPath = LogicalTreeHelper.FindLogicalNode(EntryInList, "MarkPath") as System.Windows.Shapes.Path; if ( (collection == CommentsList) && (markPath != null) ) { LinearGradientBrush lBrush = new LinearGradientBrush(); GradientStopCollection gColl = new GradientStopCollection(); GradientStop gStop = new GradientStop(Colors.LightGreen, 0); gColl.Add(gStop); lBrush.GradientStops = gColl; markPath.Fill = lBrush; } collection.Items.Add(EntryInList); TextBlock spText = LogicalTreeHelper.FindLogicalNode(EntryInList, "TB") as TextBlock; string MarkText = ""; if (spText != null) { ContentLocator cloc = ann.Anchors[0].ContentLocators[0] as ContentLocator; if (cloc == null) return; if (cloc.Parts.Count < 2) return; ContentLocatorPart cPart = cloc.Parts[1]; if (cPart == null) return; if (cPart.NameValuePairs["Segment0"] != null) { string[] charPos = cPart.NameValuePairs["Segment0"].Split(','); FlowDocument fd = FDPV.Document as FlowDocument; TextPointer tp = fd.ContentStart.GetPositionAtOffset( int.Parse(charPos[0]), LogicalDirection.Forward); if (tp == null) return; if ( tp.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text ) { MarkText += tp.GetTextInRun(LogicalDirection.Forward); } spText.Text = MarkText.Substring( 0, (MarkText.Length > 150) ? 150 : MarkText.Length ); } } }// end:AddBookmarkOrComment()
/// <summary> /// handle the case when an anchor is modified /// </summary> /// <param name="annotation">the annotation which anchor was affected</param> /// <param name="anchor">the modified anchor</param> /// <returns></returns> private AttachedAnnotationChangedEventArgs AnchorModified(Annotation annotation, AnnotationResource anchor) { Invariant.Assert(annotation != null && anchor != null, "Parameter 'annotation' or 'anchor' is null."); AttachedAnnotationChangedEventArgs args = null; AttachmentLevel newAttachmentLevel; bool previouslyAttached = false; // anchor has changed, need to find new attached anchor object newAttachedAnchor = FindAttachedAnchor(anchor, out newAttachmentLevel); // Since we will be modifying this collection, we make a copy of it to iterate on IList<IAttachedAnnotation> annotations = _annotationMap.GetAttachedAnnotations(annotation.Id); IAttachedAnnotation[] list = new IAttachedAnnotation[annotations.Count]; annotations.CopyTo(list, 0); foreach (IAttachedAnnotation attachedAnnotation in list) { if (attachedAnnotation.Anchor == anchor) { previouslyAttached = true; if (newAttachmentLevel != AttachmentLevel.Unresolved) { Invariant.Assert(newAttachedAnchor != null, "AttachedAnnotation with AttachmentLevel != Unresolved should have non-null AttachedAnchor."); object oldAttachedAnchor = attachedAnnotation.AttachedAnchor; AttachmentLevel oldAttachmentLevel = attachedAnnotation.AttachmentLevel; ((AttachedAnnotation)attachedAnnotation).Update(newAttachedAnchor, newAttachmentLevel, null); // Update the full anchor FullyResolveAnchor(attachedAnnotation); // No need to update map - we just changed the AttachedAnnotation in-place args = AttachedAnnotationChangedEventArgs.Modified(attachedAnnotation, oldAttachedAnchor, oldAttachmentLevel); } else { // the new modified anchor doesn't resolve // we need to delete the original attached annotation DoRemoveAttachedAnnotation(attachedAnnotation); args = AttachedAnnotationChangedEventArgs.Deleted(attachedAnnotation); } break; } } // If it wasn't previously attached, but can be resolved now we create an AttachedAnnotation if (!previouslyAttached && newAttachmentLevel != AttachmentLevel.Unresolved && newAttachmentLevel != AttachmentLevel.Incomplete) { Invariant.Assert(newAttachedAnchor != null, "AttachedAnnotation with AttachmentLevel != Unresolved should have non-null AttachedAnchor."); AttachedAnnotation attachedAnnotation = new AttachedAnnotation( this.LocatorManager, annotation, anchor, newAttachedAnchor, newAttachmentLevel); DoAddAttachedAnnotation(attachedAnnotation); args = AttachedAnnotationChangedEventArgs.Added(attachedAnnotation); } return args; }
public static IAnchorInfo GetAnchorInfo(AnnotationService service, Annotation annotation) { return default(IAnchorInfo); }
public AnnotationResourceChangedEventArgs(Annotation annotation, AnnotationAction action, AnnotationResource resource) { }