Plugin - Get Position of selected Element
Having trouble installing Oxygen? Got a bug to report? Post it all here.
-
- Posts: 96
- Joined: Mon May 09, 2011 11:54 am
Plugin - Get Position of selected Element
Hi,
is it possible to get the current absolute xpath or a position of a selection through a custom plugin? Eg. i have the following structure:
<doc>
<sec/>
<sec/>
<sec/>
</doc>
and I want to click e.g. on one of the sec's and get a message like "You are here: /doc/sec[2]/p/xy" or "You are in the 2. Section"
I hope you understand my question
Thanks,
Patrick
is it possible to get the current absolute xpath or a position of a selection through a custom plugin? Eg. i have the following structure:
<doc>
<sec/>
<sec/>
<sec/>
</doc>
and I want to click e.g. on one of the sec's and get a message like "You are here: /doc/sec[2]/p/xy" or "You are in the 2. Section"
I hope you understand my question

Thanks,
Patrick
-
- Posts: 9439
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Plugin - Get Position of selected Element
Hi Patrick,
What kind of plugin did you implement?
In the Text mode the API of the ro.sync.exml.workspace.api.editor.page.text.xml.WSXMLTextEditorPage contains a method called:evaluateXPath(String).
The XPath is evaluated in the context of the XML element on which the caret is located. So if you evaluate and XPath like . you will get the DOM node equivalent of the current XML element. From this DOM node you can compose the XPath string you are after by navigating it.
Equivalent, in the Author mode you have WSAuthorEditorPage.getDocumentController().evaluateXPath(...)
Regards,
Radu
For the Text or for the Author mode?is it possible to get the current absolute xpath or a position of a selection through a custom plugin?
What kind of plugin did you implement?
In the Text mode the API of the ro.sync.exml.workspace.api.editor.page.text.xml.WSXMLTextEditorPage contains a method called:evaluateXPath(String).
The XPath is evaluated in the context of the XML element on which the caret is located. So if you evaluate and XPath like . you will get the DOM node equivalent of the current XML element. From this DOM node you can compose the XPath string you are after by navigating it.
Equivalent, in the Author mode you have WSAuthorEditorPage.getDocumentController().evaluateXPath(...)
The NodeRendererCustomizer does not have access to this API but it has access to the current AuthorNode which can be used to navigate the AuthorNode structure and thus look for siblings of the current node and so on.It would be also great if I can access these information in the oultine view through the NodeRendererCustomizer to number the sections there.
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 96
- Joined: Mon May 09, 2011 11:54 am
Re: Plugin - Get Position of selected Element
Its the Text mode. In the author mode it's already implemented in the stylesheet but in the text mode such a function would be helpful in our large documents.
I will try it with these methods.
I will try it with these methods.
-
- Posts: 9439
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Plugin - Get Position of selected Element
Hi Patrick,
I do not quite understand what your final goal is: a contextual menu actions in the Text page or to customize the name (or tooltip) of a node in the Outline view. Or both?
If you right click in the Text page there is already a "Copy XPath" operation which sets in the clipboard the XPath of the current node.
Regards,
Radu
I do not quite understand what your final goal is: a contextual menu actions in the Text page or to customize the name (or tooltip) of a node in the Outline view. Or both?
If you right click in the Text page there is already a "Copy XPath" operation which sets in the clipboard the XPath of the current node.
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 96
- Joined: Mon May 09, 2011 11:54 am
Re: Plugin - Get Position of selected Element
Ok, the perfect solution would be sth. like this (equal to the navigation tree in Word):
The result should be:
doc "15"
sec Introduction
sec 15 Section title
sec 15.1 Section title
sec 16 Section title
2nd the "Copy Xpath": Is it possible to configure the "Xpath update on caret move" to display the exact Xpath as Copy Xpath does?
- Highlight current position (given in outline view)
- Linked with document on click (given in outline view)
- Set filter and hide other elements (given in outline view, example sec)
- Number the structure elements (e.g. 1st level n, 2nd n.n, 3rd n.n.n) which are not excluded (e.g. xapth sec[not(@counter='no')])
- Set start number (eg. xpath /doc/@startnumber)
- Specify an element which content is displayed as title of the structured element (e.g. xpath title[1])
- Possibility to predefine some settings through a framework (will write an separate post)
Code: Select all
<doc startnumber="15">
<sec counter="no">
<!-- Some comment -->
<info/>
<title>Introduction</title>
</sec>
<sec>
<title>Section title</title>
<para>Content</para>
<sec>
<title>Section title</title>
<para>Content</para>
</sec>
</sec>
<sec>
<title>Section title</title>
<para>Content</para>
</sec>
</doc>
doc "15"
sec Introduction
sec 15 Section title
sec 15.1 Section title
sec 16 Section title
2nd the "Copy Xpath": Is it possible to configure the "Xpath update on caret move" to display the exact Xpath as Copy Xpath does?
-
- Posts: 9439
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Plugin - Get Position of selected Element
Hi Patrick,
Regards,
Radu
This surpasses our current API possibilities. What you could do would probably be to implement your own custom view and set it up from a Workspace Access plugin. Then you would have full control over what needs to be presented in the Outline tree.Ok, the perfect solution would be sth. like this (equal to the navigation tree in Word):....
No, it is not. The idea of the XPath toolbar auto-updating when the user moved the caret has that you could copy the XPath from there and paste it in an XSLT stylesheet so it was intended to be more generic without pointing to a specific node index. But we will discuss this internally and if we decide to do something I'll update this thread.2nd the "Copy Xpath": Is it possible to configure the "Xpath update on caret move" to display the exact Xpath as Copy Xpath does?
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 9439
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Plugin - Get Position of selected Element
Hi Patrick,
Using our Plugins SDK:
http://www.oxygenxml.com/oxygen_sdk.htm ... er_Plugins
you can write a Workspace Access plugin which contributes with a custom view showing a simplified outline structure of the XML opened in the Text mode.
I tried writing such an example using the API to perform XPaths over the XML document and present its simplified structure in a list:
Regards,
Radu
Using our Plugins SDK:
http://www.oxygenxml.com/oxygen_sdk.htm ... er_Plugins
you can write a Workspace Access plugin which contributes with a custom view showing a simplified outline structure of the XML opened in the Text mode.
I tried writing such an example using the API to perform XPaths over the XML document and present its simplified structure in a list:
Code: Select all
/**
* Simple Outline for the Text mode based on executing XPaths over the text content.
*/
public class CustomWorkspaceAccessPluginExtension implements WorkspaceAccessPluginExtension {
/**
* The custom outline list.
*/
private JList customOutlineList;
/**
* Maps outline nodes to ranges in document
*/
private WSXMLTextNodeRange[] currentOutlineRanges;
/**
* The current text page
*/
private WSXMLTextEditorPage currentTextPage;
/**
* Disable caret listener when we select from the caret listener.
*/
private boolean enableCaretListener = true;
/**
* @see ro.sync.exml.plugin.workspace.WorkspaceAccessPluginExtension#applicationStarted(ro.sync.exml.workspace.api.standalone.StandalonePluginWorkspace)
*/
@Override
public void applicationStarted(final StandalonePluginWorkspace pluginWorkspaceAccess) {
pluginWorkspaceAccess.addViewComponentCustomizer(new ViewComponentCustomizer() {
/**
* @see ro.sync.exml.workspace.api.standalone.ViewComponentCustomizer#customizeView(ro.sync.exml.workspace.api.standalone.ViewInfo)
*/
@Override
public void customizeView(ViewInfo viewInfo) {
if(
//The view ID defined in the "plugin.xml"
"SampleWorkspaceAccessID".equals(viewInfo.getViewID())) {
customOutlineList = new JList();
//Render the content in the Outline.
customOutlineList.setCellRenderer(new DefaultListCellRenderer() {
/**
* @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean)
*/
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
String val = null;
if(value instanceof Element) {
Element element = ((Element)value);
val = element.getNodeName();
if(!"".equals(element.getAttribute("startnumber"))) {
val += " " + "'" + element.getAttribute("startnumber") + "'";
}
NodeList titles = element.getElementsByTagName("title");
if(titles.getLength() > 0) {
val += " \"" + titles.item(0).getTextContent() + "\"";
}
}
label.setText(val);
return label;
}
});
//When we click a node, select it in the text page.
customOutlineList.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
int sel = customOutlineList.getSelectedIndex();
enableCaretListener = false;
try {
currentTextPage.select(currentTextPage.getOffsetOfLineStart(currentOutlineRanges[sel].getStartLine()) + currentOutlineRanges[sel].getStartColumn() - 1,
currentTextPage.getOffsetOfLineStart(currentOutlineRanges[sel].getEndLine()) + currentOutlineRanges[sel].getEndColumn());
} catch (BadLocationException e1) {
e1.printStackTrace();
}
enableCaretListener = true;
}
}
});
viewInfo.setComponent(new JScrollPane(customOutlineList));
viewInfo.setTitle("Custom Outline");
}
}
});
pluginWorkspaceAccess.addEditorChangeListener(new WSEditorChangeListener() {
/**
* @see ro.sync.exml.workspace.api.listeners.WSEditorChangeListener#editorOpened(java.net.URL)
*/
@Override
public void editorOpened(URL editorLocation) {
//An editor was opened
WSEditor editorAccess = pluginWorkspaceAccess.getEditorAccess(editorLocation, StandalonePluginWorkspace.MAIN_EDITING_AREA);
if(editorAccess != null) {
WSEditorPage currentPage = editorAccess.getCurrentPage();
if(currentPage instanceof WSXMLTextEditorPage) {
//User editing in Text mode an opened XML document.
final WSXMLTextEditorPage xmlTP = (WSXMLTextEditorPage) currentPage;
//Reconfigure outline on each change.
xmlTP.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
reconfigureOutline(xmlTP);
}
@Override
public void insertUpdate(DocumentEvent e) {
reconfigureOutline(xmlTP);
}
@Override
public void changedUpdate(DocumentEvent e) {
reconfigureOutline(xmlTP);
}
});
JTextArea textComponent = (JTextArea) xmlTP.getTextComponent();
textComponent.addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent e) {
if(currentOutlineRanges != null && currentTextPage != null && enableCaretListener) {
enableCaretListener = false;
//Find the node to select in the outline.
try {
int line = xmlTP.getLineOfOffset(e.getDot());
for (int i = currentOutlineRanges.length - 1; i >= 0; i--) {
if(line > currentOutlineRanges[i].getStartLine() && line < currentOutlineRanges[i].getEndLine()) {
customOutlineList.setSelectedIndex(i);
break;
}
}
} catch (BadLocationException e1) {
e1.printStackTrace();
}
enableCaretListener = true;
}
}
});
}
}
}
/**
* @see ro.sync.exml.workspace.api.listeners.WSEditorChangeListener#editorActivated(java.net.URL)
*/
@Override
public void editorActivated(URL editorLocation) {
//An editor was selected, reconfigure the common outline
WSEditor editorAccess = pluginWorkspaceAccess.getEditorAccess(editorLocation, StandalonePluginWorkspace.MAIN_EDITING_AREA);
if(editorAccess != null) {
WSEditorPage currentPage = editorAccess.getCurrentPage();
if(currentPage instanceof WSXMLTextEditorPage) {
//User editing in Text mode an opened XML document.
WSXMLTextEditorPage xmlTP = (WSXMLTextEditorPage) currentPage;
reconfigureOutline(xmlTP);
}
}
}
}, StandalonePluginWorkspace.MAIN_EDITING_AREA);
}
/**
* Reconfigure the outline
*
* @param xmlTP The XML Text page.
*/
protected void reconfigureOutline(final WSXMLTextEditorPage xmlTP) {
try {
//These are DOM nodes.
Object[] evaluateXPath = xmlTP.evaluateXPath("//doc | //sec");
//These are the ranges each node takes in the document.
currentOutlineRanges = xmlTP.findElementsByXPath("//doc | //sec");
currentTextPage = xmlTP;
DefaultListModel listModel = new DefaultListModel();
if(evaluateXPath != null) {
for (int i = 0; i < evaluateXPath.length; i++) {
listModel.addElement(evaluateXPath[i]);
}
}
customOutlineList.setModel(listModel);
} catch(XPathException ex) {
ex.printStackTrace();
}
}
/**
* @see ro.sync.exml.plugin.workspace.WorkspaceAccessPluginExtension#applicationClosing()
*/
@Override
public boolean applicationClosing() {
return true;
}
}
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 96
- Joined: Mon May 09, 2011 11:54 am
Re: Plugin - Get Position of selected Element
Hi Radu,
it's a long time ago, but now I have written a plugin based up on your example. To count the section numbers, I call a function with the root Element and process it.
But what is the fastest way to get the root Element Node?
Currently I use Object[] evaluateXPath = xmlTP.evaluateXPath("/*") where xmlTP is a WSXMLTextEditorPage and use evaluateXPath[0] as root Element. It works but it takes ~700ms for the XPath Evaluation, which is 3/4 of the total running time of the plugin.
Thanks,
Patrick
it's a long time ago, but now I have written a plugin based up on your example. To count the section numbers, I call a function with the root Element and process it.
But what is the fastest way to get the root Element Node?
Currently I use Object[] evaluateXPath = xmlTP.evaluateXPath("/*") where xmlTP is a WSXMLTextEditorPage and use evaluateXPath[0] as root Element. It works but it takes ~700ms for the XPath Evaluation, which is 3/4 of the total running time of the plugin.
Thanks,
Patrick
-
- Posts: 9439
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Plugin - Get Position of selected Element
Hi Patrick,
There's nothing wrong with your XPath, afak it is the fastest way to get the root element but the XPath is run over the entire XML content and as the XML content might be quite large, the XPath will take some time.
For out Outline implementations we use a technique called event coalescing.
For example if you are editing in the Text mode and you insert fast an new element, the quickly insert content in it, the Outline does not change during these quick modifications, it waits for the events to die out before it reacts and reconfigures. This is usually done using a timer and scheduling a task on it after the previous task has been canceled.
So as a conclusion you should avoid running many XPath queries one after the other and run the queries on another thread so that the GUI is not blocked, then update the Outline on the AWT thread when the query is done.
Regards,
Radu
There's nothing wrong with your XPath, afak it is the fastest way to get the root element but the XPath is run over the entire XML content and as the XML content might be quite large, the XPath will take some time.
For out Outline implementations we use a technique called event coalescing.
For example if you are editing in the Text mode and you insert fast an new element, the quickly insert content in it, the Outline does not change during these quick modifications, it waits for the events to die out before it reacts and reconfigures. This is usually done using a timer and scheduling a task on it after the previous task has been canceled.
Code: Select all
TimerTask currentTask = null;
.......................
final JTextArea textArea = (JTextArea) xmlTextPage.getTextComponent();
final java.util.Timer timer = new Timer();
textArea.addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent e) {
//caret moved
if(currentTask != null) {
//Cancel pending tasks, we will update the outline 500 ms after the last caret change has occured.
currentTask.cancel();
}
currentTask = new TimerTask() {
@Override
public void run() {
//Here you find nodes by XPath
//This is done on thread so it will not block the UI
// xmlTextPage.findElementsByXPath("/*");
//Then reconfigure the outline on the AWT thread.
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
//Maybe based on the caret location you select the proper node
// textArea.getCaretPosition();
}
});
} catch (Exception e) {
e.printStackTrace();
e.printStackTrace();
}
}
};
timer.schedule(currentTask, 500);
}
});
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 96
- Joined: Mon May 09, 2011 11:54 am
Re: Plugin - Get Position of selected Element
Hi Radu,
another question: I select The Text from the Selected Outline item with WSXMLTextEditorPage.select() but how to get the editor view to scroll to the beginning of the selection like the original outline view does? Currently I think it scrolls to the middle of the selection.
another question: I select The Text from the Selected Outline item with WSXMLTextEditorPage.select() but how to get the editor view to scroll to the beginning of the selection like the original outline view does? Currently I think it scrolls to the middle of the selection.
-
- Posts: 9439
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Plugin - Get Position of selected Element
Hi Patrick,
You could try to call the API to make the selection from the end offset to the start one like WSTextBasedEditorPage.select(endSelOffset, startSelOffset), this should move the scroll to the beginning of the element as you want, that's how we do it in our Outline.
In the worst case you can get access to the Swing JTextArea WSTextEditorPage.getTextComponent() and scroll to whatever offset you want.
Regards,
Radu
You could try to call the API to make the selection from the end offset to the start one like WSTextBasedEditorPage.select(endSelOffset, startSelOffset), this should move the scroll to the beginning of the element as you want, that's how we do it in our Outline.
In the worst case you can get access to the Swing JTextArea WSTextEditorPage.getTextComponent() and scroll to whatever offset you want.
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 96
- Joined: Mon May 09, 2011 11:54 am
Re: Plugin - Get Position of selected Element
Hi Radu,
can you help me how to do that? I have tried it this way but then nothing is selected anymore. It seems that select needs the minor value first:
can you help me how to do that? I have tried it this way but then nothing is selected anymore. It seems that select needs the minor value first:
Code: Select all
currentTextPage.select(
currentTextPage.getOffsetOfLineStart(currentOutlineRanges[endsel].getEndLine()) + currentOutlineRanges[endsel].getEndColumn(),
currentTextPage.getOffsetOfLineStart(currentOutlineRanges[startsel].getStartLine()) + currentOutlineRanges[startsel].getStartColumn() + 1
);
-
- Posts: 9439
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Plugin - Get Position of selected Element
Hi Patrick,
I tested with an Oxygen 15.2 standalone installation with the same code sample for the XPath based outliner I previously posted on the thread and the selection worked for me.
This might not work if you are using Oxygen 15.0 or older (there was an issue for the same selection API fixed in 15.1).
An alternative would be something like this:
Regards,
Radu
I tested with an Oxygen 15.2 standalone installation with the same code sample for the XPath based outliner I previously posted on the thread and the selection worked for me.
This might not work if you are using Oxygen 15.0 or older (there was an issue for the same selection API fixed in 15.1).
An alternative would be something like this:
Code: Select all
final int startOffset = currentTextPage.getOffsetOfLineStart(currentOutlineRanges[sel].getStartLine()) + currentOutlineRanges[sel].getStartColumn() - 1;
currentTextPage.select(startOffset,
currentTextPage.getOffsetOfLineStart(currentOutlineRanges[sel].getEndLine()) + currentOutlineRanges[sel].getEndColumn());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JTextArea textComponent = (JTextArea) currentTextPage.getTextComponent();
try {
Rectangle startOffsetRect = textComponent.modelToView(startOffset);
textComponent.scrollRectToVisible(startOffsetRect);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
});
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 9439
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Plugin - Get Position of selected Element
Hi Patrick,
You could try do add an ancestor listener to the JTree something like:
and look if the isShowing() state has changed on it. If it has changed, look if the view was hidden and disconnect it from the event listeners or look if it was shown and re-connect it to the listeners + refresh its content.
Regards,
Radu
You could try do add an ancestor listener to the JTree something like:
Code: Select all
boolean currentShowing = jTree.isShowing();
jTree.addAncestorListener(new AncestorListener() {
@Override
public void ancestorRemoved(AncestorEvent event) {
reconfigureCurrentShowing();
}
@Override
public void ancestorMoved(AncestorEvent event) {
}
@Override
public void ancestorAdded(AncestorEvent event) {
reconfigureCurrentShowing();
}
private void reconfigureCurrentShowing() {
if(currentShowing != jTree.isShowing()) {
//Tree was either hidden or shown
}
}
});
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
Jump to
- Oxygen XML Editor/Author/Developer
- ↳ Feature Request
- ↳ Common Problems
- ↳ DITA (Editing and Publishing DITA Content)
- ↳ SDK-API, Frameworks - Document Types
- ↳ DocBook
- ↳ TEI
- ↳ XHTML
- ↳ Other Issues
- Oxygen XML Web Author
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Content Fusion
- ↳ Feature Request
- ↳ Common Problems
- Oxygen JSON Editor
- ↳ Feature Request
- ↳ Common Problems
- Oxygen PDF Chemistry
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Feedback
- ↳ Feature Request
- ↳ Common Problems
- Oxygen XML WebHelp
- ↳ Feature Request
- ↳ Common Problems
- XML
- ↳ General XML Questions
- ↳ XSLT and FOP
- ↳ XML Schemas
- ↳ XQuery
- NVDL
- ↳ General NVDL Issues
- ↳ oNVDL Related Issues
- XML Services Market
- ↳ Offer a Service