private void ExpandBuffer() { // Buffer is too smal for this amount of attributes. Debug.Assert(writePos == readStartPos + buffer.Length, "no space to write next token"); Debug.Assert(writePos == readEndPos, "all tokens ware read"); int newMask = (mask << 1) | 1; XmlToken[] newBuffer = new XmlToken[newMask + 1]; for (int i = readStartPos; i < writePos; i++) { newBuffer[i & newMask] = buffer[i & mask]; } buffer = newBuffer; mask = newMask; Debug.Assert(writePos < readStartPos + buffer.Length, "we should have now space to next write token"); }
/// <summary> /// Update the metadata tokens specified in token. /// </summary> private static void UpdateMetaData(XmlToken token, StickyNoteControl snc, SNCAnnotation sncAnnotation) { bool newCargo, newRoot; AnnotationResource cargo; XmlElement root; GetCargoAndRoot(sncAnnotation, XmlToken.MetaData, out cargo, out root, out newCargo, out newRoot); // Update Expanded if ((token & XmlToken.IsExpanded) != 0) { bool expanded = snc.IsExpanded; sncAnnotation.UpdateAttribute(root, XmlToken.IsExpanded, expanded.ToString(CultureInfo.InvariantCulture)); } // Update Height if ((token & XmlToken.Height) != 0) { Debug.Assert(snc.IsExpanded); double height = (double)snc.GetValue(FrameworkElement.HeightProperty); sncAnnotation.UpdateAttribute(root, XmlToken.Height, height.ToString(CultureInfo.InvariantCulture)); } // Update Width if ((token & XmlToken.Width) != 0) { Debug.Assert(snc.IsExpanded); double width = (double)snc.GetValue(FrameworkElement.WidthProperty); sncAnnotation.UpdateAttribute(root, XmlToken.Width, width.ToString(CultureInfo.InvariantCulture)); } // Update Left if ((token & XmlToken.Left) != 0) { double left = snc.PositionTransform.X; // All 'left' values are persisted assuming two things: // 1) the top-left corner (visually) of the StickyNote is the origin of its coordinate space // 2) the positive x-axis of its parent is to the right // This flag signals that we have a positive x-axis to the left and our // top-right corner (visually) is our origin. So we need to flip the // value before persisting it. if (snc.FlipBothOrigins) { left = -(left + snc.Width); } sncAnnotation.UpdateAttribute(root, XmlToken.Left, left.ToString(CultureInfo.InvariantCulture)); } // Update Top if ((token & XmlToken.Top) != 0) { sncAnnotation.UpdateAttribute(root, XmlToken.Top, snc.PositionTransform.Y.ToString(CultureInfo.InvariantCulture)); } // Update XOffset if ((token & XmlToken.XOffset) != 0) { sncAnnotation.UpdateAttribute(root, XmlToken.XOffset, snc.XOffset.ToString(CultureInfo.InvariantCulture)); } // Update YOffset if ((token & XmlToken.YOffset) != 0) { sncAnnotation.UpdateAttribute(root, XmlToken.YOffset, snc.YOffset.ToString(CultureInfo.InvariantCulture)); } // Update ZOrder if ((token & XmlToken.ZOrder) != 0) { sncAnnotation.UpdateAttribute(root, XmlToken.ZOrder, ((IAnnotationComponent)snc).ZOrder.ToString(CultureInfo.InvariantCulture)); } if (newRoot) { cargo.Contents.Add(root); } if (newCargo) { sncAnnotation._annotation.Cargos.Add(cargo); } }
public virtual void Write(XmlNodeType nodeType, QName name, string value) { Debug.Assert(writePos <= buffer.Length); if (writePos == buffer.Length) { XmlToken[] temp = new XmlToken[buffer.Length * 2]; buffer.CopyTo(temp, 0); buffer = temp; } Debug.Assert(writePos < buffer.Length); XmlToken.Set(ref buffer[writePos], nodeType, name, value); writePos++; }
/// <summary> /// Find the specified data in a cargo. /// </summary> /// <param name="token">The specified data</param> /// <param name="cargo">The cargo which we are searhing in</param> /// <returns>The data object or null</returns> private static object FindContent(XmlToken token, AnnotationResource cargo) { object content = null; XmlElement root = SNCAnnotation.FindRootXmlElement(token, cargo); // If we found the root node, we should use XPath to query the node which contains the corresponding data. // The StickyNoteControl's xml schema can be found // in http://tabletpc/longhorn/Specs/WinFX%20StickyNoteControl%20M8.1.mht#_Toc79371211 if (root != null) { switch (token) { case XmlToken.Text: case XmlToken.Ink: return root; case XmlToken.IsExpanded: case XmlToken.ZOrder: case XmlToken.Top: case XmlToken.Left: case XmlToken.XOffset: case XmlToken.YOffset: case XmlToken.Width: case XmlToken.Height: return root.GetAttributeNode(GetXmlName(token), AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); default: Debug.Assert(false); break; } } return content; }
// Update ink data from/to SNC. private void UpdateContent(StickyNoteControl snc, bool updateAnnotation, XmlToken token) { Invariant.Assert(snc != null, "Sticky Note Control is null."); Invariant.Assert((token & AllContents) != 0, "No token specified."); StickyNoteContentControl contentControl = snc.Content; // Template hasn't been applied yet. Once it has the content control will then be setup. if (contentControl == null) { return; } // Check whether the annotation data matches the content control. if ((token == XmlToken.Ink && contentControl.Type != StickyNoteType.Ink) || (token == XmlToken.Text && contentControl.Type != StickyNoteType.Text)) { Debug.Assert(false, "The annotation data does match with the current content control in StickyNote"); return; } XmlElement root = null; if (updateAnnotation) { // Update annotation from SNC AnnotationResource cargo = null; bool newRoot = false; bool newCargo = false; // Check if the text is empty. if (!contentControl.IsEmpty) { GetCargoAndRoot(this, token, out cargo, out root, out newCargo, out newRoot); contentControl.Save(root); } else { string cargoName = GetCargoName(token); cargo = FindCargo(cargoName); if (cargo != null) { _annotation.Cargos.Remove(cargo); _cachedXmlElements.Remove(token); } } if (newRoot) { Invariant.Assert(root != null, "XmlElement should have been created."); Invariant.Assert(cargo != null, "Cargo should have been retrieved."); cargo.Contents.Add(root); } if (newCargo) { Invariant.Assert(cargo != null, "Cargo should have been created."); _annotation.Cargos.Add(cargo); } } else { // Update SNC from annotation // Check if we have the text data in the xml store. XmlElement node = (XmlElement)FindData(token); if (node != null) { contentControl.Load(node); } else { if (!contentControl.IsEmpty) { contentControl.Clear(); } } } }
/// <summary> /// This method will update this StickyNoteControl data based on the internal annotation variable. /// </summary> /// <param name="tokens">The data need to be updated</param> private void UpdateSNCWithAnnotation(XmlToken tokens) { if (_sncAnnotation != null) { //fire trace event EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.UpdateSNCWithAnnotationBegin); // Now, we are going to update this StickyNoteControl. We will get notified for the data being changed. // we don't want to update our internal annotation because for the data changes which are coming // from the annotation itself. So, we lock our internal locker. using (LockHelper.AutoLocker locker = new LockHelper.AutoLocker(InternalLocker, LockHelper.LockFlag.DataChanged)) { SNCAnnotation.UpdateStickyNoteControl(tokens, this, _sncAnnotation); } //fire trace event EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.UpdateSNCWithAnnotationEnd); } }
/// <summary> /// The method returns the root node which contains the specified data in a cargo. /// </summary> /// <param name="token">The specified data</param> /// <param name="cargo">The specified cargo</param> /// <returns>The root node or null</returns> private static XmlElement FindRootXmlElement(XmlToken token, AnnotationResource cargo) { Debug.Assert(cargo != null); XmlElement element = null; string xmlName = string.Empty; // Get the xml name of the root node switch (token) { case XmlToken.Text: case XmlToken.Ink: xmlName = GetXmlName(token); break; case XmlToken.MetaData: case XmlToken.IsExpanded: case XmlToken.Width: case XmlToken.Height: case XmlToken.Top: case XmlToken.Left: case XmlToken.XOffset: case XmlToken.YOffset: case XmlToken.ZOrder: xmlName = GetXmlName(XmlToken.MetaData); break; default: Debug.Assert(false); break; } // Search the root in the cargo's contents. foreach (XmlElement node in cargo.Contents) { if (node.Name.Equals(xmlName)) { element = node; break; } } return element; }
/// <summary> /// This static method returns the Xml name for the specified token. /// </summary> /// <param name="token">A specified token</param> /// <returns>The name for the Xml node</returns> private static string GetXmlName(XmlToken token) { return s_xmlTokeFullNames[token]; }
/// <summary> /// This method is called by the static constructor to set up the Xml name dictionary. /// </summary> /// <param name="token">A specified token</param> private static void AddXmlTokenNames(XmlToken token) { // Conver the enum value to the string first. string xmlName = token.ToString(); // Depending on the data, we add the proper prefix to the full name. switch (token) { // The element names should be qualified case XmlToken.MetaData: case XmlToken.Text: case XmlToken.Ink: { s_xmlTokeFullNames.Add(token, AnnotationXmlConstants.Prefixes.BaseSchemaPrefix + ":" + xmlName); } break; //the attribute names should be local case XmlToken.Left: case XmlToken.Top: case XmlToken.XOffset: case XmlToken.YOffset: case XmlToken.Width: case XmlToken.Height: case XmlToken.IsExpanded: case XmlToken.ZOrder: default: { s_xmlTokeFullNames.Add(token, xmlName); } break; } }
/// <summary> /// Returns the AnnotationResource and the XML root for the given token from the passed in annotation. /// If the cargo or root do not exist they are created but not added to the annotation. The newCargo /// and newRoot flags specify whether they were created. The caller must use these to add the items /// to the annotation after they are done with their modifications. /// </summary> /// <param name="annotation">the current annotation</param> /// <param name="token">the token to be processed</param> /// <param name="cargo">the cargo for the token</param> /// <param name="root">the root XML element</param> /// <param name="newCargo">means a new root and new cargo was created. the root was already added to the cargo but the cargo was not added to the annotation</param> /// <param name="newRoot">means a new root was created. it has not been added to the cargo.</param> private static void GetCargoAndRoot( SNCAnnotation annotation, XmlToken token, out AnnotationResource cargo, out XmlElement root, out bool newCargo, out bool newRoot) { Invariant.Assert(annotation != null, "Annotation is null."); Invariant.Assert((token & (AllValues | XmlToken.MetaData)) != 0, "No token specified."); string cargoName = GetCargoName(token); newRoot = false; newCargo = false; cargo = annotation.FindCargo(cargoName); // Cargo exists if (cargo != null) { root = FindRootXmlElement(token, cargo); // Uncommon situation - cargo created without root XmlElement if (root == null) { newRoot = true; XmlDocument xmlDoc = new XmlDocument(); root = xmlDoc.CreateElement(GetXmlName(token), AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); // Don't add it to the cargo yet - wait until all the // values are set on it } } else { newCargo = true; cargo = new AnnotationResource(cargoName); XmlDocument xmlDoc = new XmlDocument(); root = xmlDoc.CreateElement(GetXmlName(token), AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); // Since the cargo is new, its safe to add the root to it // No events will make it to the annotation yet cargo.Contents.Add(root); } }
/// <summary> /// Updates the value of the specified token on the specified XmlElement. /// If the value is the same, no update is made. If the new value is null /// the attribute is removed. /// </summary> private void UpdateAttribute(XmlElement root, XmlToken token, string value) { string name = GetXmlName(token); XmlNode oldValue = root.GetAttributeNode(name, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); if (oldValue == null) { if (value == null) return; else root.SetAttribute(name, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace, value); } else { if (value == null) root.RemoveAttribute(name, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); else if (oldValue.Value != value) root.SetAttribute(name, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace, value); } }
/// <summary> /// Find the specified Annotation data /// </summary> /// <param name="token">A flag which is corresponding to the annotation data</param> /// <returns>The annotation data or null</returns> private object FindData(XmlToken token) { // Assume that we can't find any thing. object ret = null; // First, check if we have the data cached. if (_cachedXmlElements.ContainsKey(token)) { ret = _cachedXmlElements[token]; } else { // Then, we try to search the data in the current annotation. AnnotationResource cargo = FindCargo(GetCargoName(token)); if (cargo != null) { ret = SNCAnnotation.FindContent(token, cargo); // If we found the data in annotation, we go ahead cache it. if (ret != null) { _cachedXmlElements.Add(token, ret); } } } return ret; }
/// <summary> /// This static method will update a StickyNoteControl object with the specified data in an Annotation /// </summary> /// <param name="token">A flag which indicates the data needs to be updated. The flag can be combinated with the any valid bits.</param> /// <param name="snc">A StickyNoteControl instance</param> /// <param name="sncAnnotation">An SNCAnnotation object which contains a CAF annotation object</param> public static void UpdateStickyNoteControl(XmlToken token, StickyNoteControl snc, SNCAnnotation sncAnnotation) { Invariant.Assert((token & AllValues) != 0, "No token specified."); Invariant.Assert(snc != null, "Sticky Note Control is null."); Invariant.Assert(sncAnnotation != null, "Annotation is null."); // XmlAttribute node; // Update Ink if ((token & XmlToken.Ink) != 0 && sncAnnotation.HasInkData) { sncAnnotation.UpdateContent(snc, false, XmlToken.Ink); } // Update Text if ((token & XmlToken.Text) != 0 && sncAnnotation.HasTextData) { sncAnnotation.UpdateContent(snc, false, XmlToken.Text); } // Update Author if ((token & XmlToken.Author) != 0) { int nCount = sncAnnotation._annotation.Authors.Count; // Get the culture specific text separator. string listSeparator = snc.Language.GetSpecificCulture().TextInfo.ListSeparator; string authors = string.Empty; for (int i = 0; i < nCount; i++) { if (i != 0) { authors += listSeparator + sncAnnotation._annotation.Authors[i]; } else { authors += sncAnnotation._annotation.Authors[i]; } } // Setting the author property will cause the UI to update snc.SetValue(StickyNoteControl.AuthorPropertyKey, authors); } // Update Height if ((token & XmlToken.Height) != 0) { node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Height); if (node != null) { double height = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); snc.SetValue(FrameworkElement.HeightProperty, height); } else { snc.ClearValue(FrameworkElement.HeightProperty); } } // Update Width if ((token & XmlToken.Width) != 0) { node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Width); if (node != null) { double width = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); snc.SetValue(FrameworkElement.WidthProperty, width); } else { snc.ClearValue(FrameworkElement.WidthProperty); } } // Update IsExpanded if ((token & XmlToken.IsExpanded) != 0) { node = (XmlAttribute)sncAnnotation.FindData(XmlToken.IsExpanded); if (node != null) { bool expanded = Convert.ToBoolean(node.Value, CultureInfo.InvariantCulture); snc.IsExpanded = expanded; } else { snc.ClearValue(StickyNoteControl.IsExpandedProperty); } } // Update ZOrder if ((token & XmlToken.ZOrder) != 0) { node = (XmlAttribute)sncAnnotation.FindData(XmlToken.ZOrder); if (node != null) { ((IAnnotationComponent)snc).ZOrder = Convert.ToInt32(node.Value, CultureInfo.InvariantCulture); } } // Update Position if ((token & PositionValues) != 0) { TranslateTransform transform = new TranslateTransform(); if ((token & XmlToken.Left) != 0) { node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Left); if (node != null) { double left = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); // All 'left' values are persisted assuming two things: // 1) the top-left corner (visually) of the StickyNote is the origin of its coordinate space // 2) the positive x-axis of its parent is to the right // This flag signals that we have a positive x-axis to the left and our // top-right corner (visually) is our origin. So we need to flip the // value before using it. if (snc.FlipBothOrigins) { left = -(left + snc.Width); } transform.X = left; } } if ((token & XmlToken.Top) != 0) { node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Top); if (node != null) { double top = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); transform.Y = top; } } // Now, we update the StickyNote offset if ((token & XmlToken.XOffset) != 0) { node = (XmlAttribute)sncAnnotation.FindData(XmlToken.XOffset); if (node != null) { snc.XOffset = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); } } if ((token & XmlToken.YOffset) != 0) { node = (XmlAttribute)sncAnnotation.FindData(XmlToken.YOffset); if (node != null) { snc.YOffset = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); } } // Set the adorner layer transform. snc.PositionTransform = transform; } }
/// <summary> /// This method will update this internal annotation based on this StickyNoteControl. /// </summary> /// <param name="tokens"></param> private void UpdateAnnotationWithSNC(XmlToken tokens) { // Check if we have an annotation attached. // Also we don't want to update the annotation when the data changes are actually caused by UpdateSNCWithAnnotation. if (_sncAnnotation != null && !InternalLocker.IsLocked(LockHelper.LockFlag.DataChanged)) { //fire trace event EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.UpdateAnnotationWithSNCBegin); // Now, we are going to update the annotation. Since we will get notified from the annotation store, // we don't want to update our internal annotation if the change has been made by this instance. // Here we lock the internal locker. using (LockHelper.AutoLocker locker = new LockHelper.AutoLocker(InternalLocker, LockHelper.LockFlag.AnnotationChanged)) { // Now, update the attached annotation. SNCAnnotation.UpdateAnnotation(tokens, this, _sncAnnotation); } //fire trace event EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.UpdateAnnotationWithSNCEnd); } }
// it seams that it faster to set fields of structure in one call. // This trick is workaround of the C# limitation of declaring variable as ref to a struct. public static void Set(ref XmlToken evnt, XmlNodeType nodeType, QName name, string value) { evnt.NodeType = nodeType; evnt.Name = name; evnt.Value = value; }
/// <summary> /// Return the cargo name which hosts the specified data. /// </summary> /// <param name="token">The specified data</param> /// <returns>The host cargo name</returns> private static string GetCargoName(XmlToken token) { string cargoName; switch (token) { // Those tokens use *snc* prefix. case XmlToken.MetaData: case XmlToken.Left: case XmlToken.Top: case XmlToken.XOffset: case XmlToken.YOffset: case XmlToken.Width: case XmlToken.Height: case XmlToken.IsExpanded: case XmlToken.ZOrder: { cargoName = SNBConstants.MetaResourceName; } break; // Those tokens use *media* prefix. case XmlToken.Text: { cargoName = SNBConstants.TextResourceName; } break; case XmlToken.Ink: { cargoName = SNBConstants.InkResourceName; } break; default: { cargoName = string.Empty; Debug.Assert(false); } break; } return cargoName; }
public static void Get(ref XmlToken evnt, out XmlNodeType nodeType, out QName name, out string value) { nodeType = evnt.NodeType; name = evnt.Name; value = evnt.Value; }
//------------------------------------------------------------------------------- // // Public Methods // //------------------------------------------------------------------------------- #region Public Methods /// <summary> /// This static method will update an Annotation object with the specified data in a StickyNoteControl /// </summary> /// <param name="token">A flag which indicates the data needs to be updated. The flag can be combinated with the any valid bits.</param> /// <param name="snc">A StickyNoteControl instance</param> /// <param name="sncAnnotation">An SNCAnnotation object which contains a CAF annotation object</param> public static void UpdateAnnotation(XmlToken token, StickyNoteControl snc, SNCAnnotation sncAnnotation) { AnnotationService service = null; bool autoFlush = false; try { service = AnnotationService.GetService(((IAnnotationComponent)snc).AnnotatedElement); if (service != null && service.Store != null) { autoFlush = service.Store.AutoFlush; // Temporarily turn off autoflush until we are done // updating all the necessary values service.Store.AutoFlush = false; } Debug.Assert((token & AllValues) != 0); // Update Ink if ((token & XmlToken.Ink) != 0 && snc.Content.Type == StickyNoteType.Ink) { sncAnnotation.UpdateContent(snc, true, XmlToken.Ink); } // Update Text if ((token & XmlToken.Text) != 0 && snc.Content.Type == StickyNoteType.Text) { sncAnnotation.UpdateContent(snc, true, XmlToken.Text); } // Update MetaData if ((token & NegativeAllContents) != 0) { UpdateMetaData(token, snc, sncAnnotation); } } finally { if (service != null && service.Store != null) { // If auto flush was true before, setting it to true again should cause a flush. service.Store.AutoFlush = autoFlush; } } }