Congree API for Structure Editor

What is the Structure Editor?

The Congree Authoring Client does not use the editor API explicitly. It uses the abstraction intermediary layer (internal Congree Client API). When it comes to the implementation of this abstraction layer, each editor uses its own version. Structure Editor is one of them. It hides all the difficulties and nuances that have to be considered when implementing the internal Congree Client API (see Fig.1). Thus, the Structure Editor is not a content editor and does not have its own UI view. But at the same time, the Congree Authoring Client interacts with the Structure Editor as a full-fledged editor.


Fig.1 Сomponents interaction scheme

As shown in Fig. 1, the XML Editor is a built-in UI control to be used by an application uses somehow. Congree does not interact directly with this control. The application itself interacts with this control and informs the Structure Editor about all changes.

When do you need to use the Structure Editor?

The Structure Editor is required if the ISV application uses an XML editor which does not have a Congree integration. The Structure Editor makes it possible to integrate Congree into the application directly.

The Structure Editor provides its own API. Using this API, the ISV application can, through the Structure Editor, check any content. Congree will assume that it is working with a real editor.



How to integrate the Structure Editor into an application?


In order to integrate the Structure Editor into the application, Congree API for ISV applications should be used. Please read this article carefully before proceeding. 

The Structure Editor provides its own implementation of the ICongreeBootstrapper interface. The implementation ICongreeBootstrapper has a co-class CongreeBootstrapperComShim.

[
  uuid(6D01C672-7B61-45D3-826A-43D072EEEEB5)
]
coclass CongreeBootstrapperComShim {
    [default] interface ICongreeBootstrapperComShim;
};

The ProgId for the co-class CongreeBootstrapperComShim is "Congree.Bootstrapper.ComShim"

After creating and initializing the Congree bootstrapper, application should create the control context (method CreateControlContext  of ICongreeBootstrapper). This method accepts the VARIANT control argument. This argument is an instance of the Structure Editor.

How to create an instance of the Structure Editor?

IStructureEditor is an interface of the required editor. This interface should be implemented on ISV application side, then provided to Congree.

IStructureEditor 

IStructureEditor provides a structure editor API which is designed to work with XML editors, which have an XML as content.

[
  odl,
  uuid(680648DB-EE74-4464-8763-7A6A24982150),
  version(1.0),
  dual,
  oleautomation
]
interface IStructureEditor : IDispatch {
    [id(0x00000001), propget]
    HRESULT DocumentNode([out, retval] INode** pRetVal);
    [id(0x00000002), propget]
    HRESULT Selection([out, retval] INodeRange** pRetVal);
    [id(0x00000002), propputref]
    HRESULT Selection([in] INodeRange* pRetVal);
    [id(0x00000003)]
    HRESULT ReplaceRange(
                    [in] INodeRange* range, 
                    [in] BSTR xml, 
                    [out, retval] INodeRange** pRetVal);
    [id(0x00000004), propget]
    HRESULT NodeComparer([out, retval] INodeComparer** pRetVal);
};

Properties:

DocumentNode

Returns root node of the XML document - instance of INode with type Document.

Selection

Get/Set selected range of the editable document.

NodeComparer

Returns implementation of INodeComparer or NULL in order to use default implementation in Congree.

Methods:

ReplaceRange

Method needed to replace content of the certain range.

Parameters:

  • range - replacement range
  • xml - new range content in XML format
  • pRetVal - return value. Range of the inserted content

INode

Provides access to the XML DOM. More about XML DOM here: https://www.w3schools.com/xml/dom_intro.asp 

[
  odl,
  uuid(2151A843-32F2-42A7-A0A7-CA1A13AB0817),
  version(1.0),
  dual,
  oleautomation
]
interface INode : IDispatch {
    [id(0x00000001), propget]
    HRESULT NodeType([out, retval] short* pRetVal);
    [id(0x00000002), propget]
    HRESULT Name([out, retval] BSTR* pRetVal);
    [id(0x00000003), propget]
    HRESULT NamespaceURI([out, retval] BSTR* pRetVal);
    [id(0x00000004), propget]
    HRESULT Prefix([out, retval] BSTR* pRetVal);
    [id(0x00000005), propget]
    HRESULT Value([out, retval] BSTR* pRetVal);
    [id(0x00000006), propget]
    HRESULT PreviousSibling([out, retval] INode** pRetVal);
    [id(0x00000007), propget]
    HRESULT NextSibling([out, retval] INode** pRetVal);
    [id(0x00000008), propget]
    HRESULT FirstChild([out, retval] INode** pRetVal);
    [id(0x00000009), propget]
    HRESULT LastChild([out, retval] INode** pRetVal);
    [id(0x0000000a), propget]
    HRESULT ParentNode([out, retval] INode** pRetVal);
    [id(0x0000000b), propget]
    HRESULT DocumentNode([out, retval] INode** pRetVal);
    [id(0x0000000c), propget]
    HRESULT Attributes([out, retval] IEnumerable** pRetVal);
    [id(0x0000000e)]
    HRESULT Equals(
                    [in] INode* node, 
                    [out, retval] VARIANT_BOOL* pRetVal);
};

Properties:

NodeType

Returns type of XML node. Possible values:

Node types
	/// <summary>
	/// Supported types of IWXmlNode
	/// </summary>
	public enum NodeType : short
	{
		/// <summary>
		/// Document
		/// </summary>
		Document = 0,
		/// <summary>
		/// Element
		/// </summary>
		Element = 1,
		/// <summary>
		/// Attribute
		/// </summary>
		Attribute = 2,
		/// <summary>
		/// Text
		/// </summary>
		Text = 3,
		/// <summary>
		/// Entity Reference
		/// </summary>
		EntityReference = 4,
		/// <summary>
		/// Whitespace
		/// </summary>
		Whitespace = 5,
		/// <summary>
		/// Significant Whitespace
		/// </summary>
		SignificantWhitespace = 6
	}

Name

Returns name of the node or attribute.

NamespaceURI

Returns namespace URI of the node if exists or null.

Prefix

Returns namespace prefix of the node if exists or null.

Value

Returns node value.

PreviousSibling

Returns previous (left) sibling of the node. Can be null.

NextSibling

Returns next (right) sibling of the node. Can be null.

FirstChild

Returns the first child node. Null if childred nodes not exist or not applicable. 

LastChild

Returns the last child node. Null if childred nodes not exist or not applicable. 

ParentNode

Returns parent node. Null for root node of the document.

DocumentNode

Returns document node (node type Document).

Attributes

Returns collection of attributes of the Element node. Collection should contain INode with type Attribute and implements interface IEnumerable. Definition of IEnumerable can be found in .Net Framework types library(mscorlib.tlb).

Methods:

Equals

Method checks equality of nodes.  Return VARIANT_TRUE if nodes are the same, otherwise return VARIANT_FALSE.

INodeComparer

[
  odl,
  uuid(67C69C37-77D2-48BE-9F67-B9A675B0092D),
  version(1.0),
  dual,
  oleautomation
]
interface INodeComparer : IDispatch {
    [id(0x60020000)]
    HRESULT Compare(
                    [in] INode* x, 
                    [in] INode* y, 
                    [out, retval] long* pRetVal);
};

Methods:

Compare

Method for compare offset of two nodes. Return 1 if start offset of node x is greater than node y. Return 0 if node x has the same offset as node y. In all other cases return 1.

INodeRange

[
  odl,
  uuid(DE0B1D9A-A500-4ADA-BDED-71905048C7CF),
  version(1.0),
  dual,
  oleautomation
]
interface INodeRange : IDispatch {
    [id(0x00000001), propget]
    HRESULT BeginNode([out, retval] INode** pRetVal);
    [id(0x00000002), propget]
    HRESULT BeginOffset([out, retval] long* pRetVal);
    [id(0x00000003), propget]
    HRESULT EndNode([out, retval] INode** pRetVal);
    [id(0x00000004), propget]
    HRESULT EndOffset([out, retval] long* pRetVal);
};

Properties:

BeginNode

Returns node where range begins.

BeginOffset

Returns offset of start of the range inside BeginNode.

EndNode

Returns node where range ends.

EndOffset

Returns offset of end of the range inside EndNode.

If BeginNode/EndNode is a TextNode or Whitespace or SignificantWhitespace, then offset equals offset inside text. For all other nodes the following values are possible:

0 - offset before node

1 - offset before node content

2 - offset after node content

3 - offset after node

Exception: Offset inside EntityReference can be 0 and 1 only

IStructureEditorEvents 

In order to notify Congree about user interaction with the editor, instance of the Structure Editor should provide IStructureEditorEvents interface. Congree subscribes to the events and reacts on user actions.

[
  uuid(504996B3-6EAB-43A8-8E62-9070741D3CB0),
  version(1.0)
]
dispinterface IStructureEditorEvents {
    properties:
    methods:
        [id(0x00000001)]
        void OnDocumentChanged([in] INode* node);
        [id(0x00000002)]
        void OnSelectionChanged([in] INodeRange* range);
};

Methods:

OnDocumentChanged

Notifies about changes in document node.

  • Parameter: node - changed node

OnSelectionChanged

Notifies if selection in document was changed.

  • Parameter: range - selected range

If user moves cursor inside editor, OnSelectionChanged should also be called. In this case, begin and end offsets of the range will be the same.