XSLT Elements | +Description | +
+ xsl:stylesheet + | +The xsl:stylesheet element is always the top-level element of an XSL + stylesheet. The name xsl:transform may be used as a synonym. | +
+ xsl:template + | +The xsl:template element has an optional mode attribute. If this is + present, the template will only be matched when the same mode is used in the + invoking xsl:apply-templates element. | +
+ for-each + | +The xsl:for-each element causes iteration over the nodes selected by a + node-set expression. | +
End of the list | +
Function | +Description | +
format-number | +The format-number function converts its first argument to a string + using the format pattern string specified by the second argument and the + decimal-format named by the third argument, or the default decimal-format, + if there is no third argument | +
current | +The current function returns a node-set that has the current node as + its only member. | +
generate-id | +The generate-id function returns a string that uniquely identifies + the node in the argument node-set that is first in document order. | +
String
list.
+ */
+ private List0
if the argument object is equal to this object.
+ */
+ @Override
+ public int compareTo(CIElement other){
+ String n1 = getName() == null ? "": getName();
+ String nm1 = getNamespace() == null ? "": getNamespace();
+
+ String n2 = other.getName() == null ? "": other.getName();
+ String nm2 = other.getNamespace() == null ? "": other.getNamespace();
+
+ int result = n1.compareTo(n2);
+ if(result == 0) {
+ result = nm1.compareTo(nm2);
+ }
+ return result;
+ }
+
+ /**
+ * Return the name.
+ *
+ * @return The name.
+ */
+ @Override
+ public String toString(){
+ String toRet = String.valueOf(getName());
+ return toRet;
+ }
+
+ /**
+ * @see ro.sync.contentcompletion.xml.CIElement#hasPrefix()
+ */
+ @Override
+ public boolean hasPrefix() {
+ return getPrefix() != null && !"".equals(getPrefix());
+ }
+
+ /**
+ * @see ro.sync.contentcompletion.xml.CIElement#getPrefix()
+ */
+ @Override
+ public String getPrefix() {
+ return proxy;
+ }
+
+ /**
+ * @param modelDescription The modelDescription to set.
+ */
+ @Override
+ public void setModelDescription(String modelDescription) {
+ this.modelDescription = modelDescription;
+ }
+
+ /**
+ * @param fractionDigitsFacetValue The fractionDigitsFacetValue to set.
+ */
+ @Override
+ public void setFacetFractionDigitsValue(String fractionDigitsFacetValue) {
+ this.fractionDigitsFacetValue = fractionDigitsFacetValue;
+ }
+ /**
+ * @param maxExclusiveFacetValue The maxExclusiveFacetValue to set.
+ */
+ @Override
+ public void setFacetMaxExclusiveValue(String maxExclusiveFacetValue) {
+ this.maxExclusiveFacetValue = maxExclusiveFacetValue;
+ }
+ /**
+ * @param maxInclusiveFacetValue The maxInclusiveFacetValue to set.
+ */
+ @Override
+ public void setFacetMaxInclusiveValue(String maxInclusiveFacetValue) {
+ this.maxInclusiveFacetValue = maxInclusiveFacetValue;
+ }
+ /**
+ * @param maxLengthFacetValue The maxLengthFacetValue to set.
+ */
+ @Override
+ public void setFacetMaxLengthValue(String maxLengthFacetValue) {
+ this.maxLengthFacetValue = maxLengthFacetValue;
+ }
+ /**
+ * @param minInclusiveFacetValue The minInclusiveFacetValue to set.
+ */
+ @Override
+ public void setFacetMinInclusiveValue(String minInclusiveFacetValue) {
+ this.minInclusiveFacetValue = minInclusiveFacetValue;
+ }
+ /**
+ * @param possiblesValuesList The possiblesValuesList to set.
+ */
+ @Override
+ public void setPossiblesValues(ListString
list.
+ *
+ * @return The possible values.
+ */
+ @Override
+ public Listtrue
if it is has references.
+ */
+ public boolean hasReferences(AuthorNode node) {
+ boolean hasReferences = false;
+ if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) {
+ AuthorElement element = (AuthorElement) node;
+ if ("ref".equals(element.getLocalName())) {
+ AttrValue attrValue = element.getAttribute("location");
+ hasReferences = attrValue != null;
+ }
+ }
+ return hasReferences;
+ }
+
+ /**
+ * Returns the name of the node that contains the expanded referred content.
+ *
+ * @param node The node that contains references.
+ * @return The display name of the node.
+ */
+ public String getDisplayName(AuthorNode node) {
+ String displayName = "ref-fragment";
+ if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) {
+ AuthorElement element = (AuthorElement) node;
+ if ("ref".equals(element.getLocalName())) {
+ AttrValue attrValue = element.getAttribute("location");
+ if (attrValue != null) {
+ displayName = attrValue.getValue();
+ }
+ }
+ }
+ return displayName;
+ }
+
+ /**
+ * Resolve the references of the node.
+ *
+ * The returning SAXSource will be used for creating the referred content
+ * using the parser and source inside it.
+ *
+ * @param node The clone of the node.
+ * @param systemID The system ID of the node with references.
+ * @param authorAccess The author access implementation.
+ * @param entityResolver The entity resolver that can be used to resolve:
+ *
+ * true
if the references must be refreshed.
+ */
+ public boolean isReferenceChanged(AuthorNode node, String attributeName) {
+ return "location".equals(attributeName);
+ }
+
+ /**
+ * @return The description of the author extension.
+ */
+ public String getDescription() {
+ return "Resolves the 'ref' references";
+ }
+}
diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFSchemaAwareEditingHandler.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFSchemaAwareEditingHandler.java
new file mode 100644
index 0000000..24a1193
--- /dev/null
+++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFSchemaAwareEditingHandler.java
@@ -0,0 +1,353 @@
+package simple.documentation.framework.extensions;
+
+import java.util.List;
+
+import javax.swing.text.BadLocationException;
+
+import ro.sync.contentcompletion.xml.ContextElement;
+import ro.sync.contentcompletion.xml.WhatElementsCanGoHereContext;
+import ro.sync.ecss.extensions.api.AuthorAccess;
+import ro.sync.ecss.extensions.api.AuthorOperationException;
+import ro.sync.ecss.extensions.api.AuthorSchemaAwareEditingHandlerAdapter;
+import ro.sync.ecss.extensions.api.AuthorSchemaManager;
+import ro.sync.ecss.extensions.api.InvalidEditException;
+import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment;
+import ro.sync.ecss.extensions.api.node.AuthorElement;
+import ro.sync.ecss.extensions.api.node.AuthorNode;
+
+/**
+ * Specific editing support for SDF documents. Handles typing and paste events inside section and tables.
+ */
+public class SDFSchemaAwareEditingHandler extends AuthorSchemaAwareEditingHandlerAdapter {
+
+ private static final String SDF_NAMESPACE = "http://www.oxygenxml.com/sample/documentation";
+ /**
+ * SDF table element name.
+ */
+ private static final String SDF_TABLE = "table";
+ /**
+ * SDF table row name.
+ */
+ private static final String SDF_TABLE_ROW = "tr";
+ /**
+ * SDF table cell name.
+ */
+ private static final String SDF_TABLE_CELL = "td";
+ /**
+ * SDF section element name.
+ */
+ private static final String SECTION = "section";
+ /**
+ * SDF para element name.
+ */
+ protected static final String PARA = "para";
+ /**
+ * SDF title element name.
+ */
+ protected static final String TITLE = "title";
+
+ /**
+ * @see ro.sync.ecss.extensions.api.AuthorSchemaAwareEditingHandler#handleDelete(int, int, ro.sync.ecss.extensions.api.AuthorAccess, boolean)
+ */
+ @Override
+ public boolean handleDelete(int offset, int deleteType, AuthorAccess authorAccess, boolean wordLevel)
+ throws InvalidEditException {
+ // Not handled.
+ return false;
+ }
+
+ /**
+ * @see ro.sync.ecss.extensions.api.AuthorSchemaAwareEditingHandler#handleDeleteElementTags(ro.sync.ecss.extensions.api.node.AuthorNode, ro.sync.ecss.extensions.api.AuthorAccess)
+ */
+ @Override
+ public boolean handleDeleteElementTags(AuthorNode nodeToUnwrap, AuthorAccess authorAccess)
+ throws InvalidEditException {
+ // Not handled.
+ return false;
+ }
+
+ /**
+ * @see ro.sync.ecss.extensions.api.AuthorSchemaAwareEditingHandler#handleDeleteSelection(int, int, int, ro.sync.ecss.extensions.api.AuthorAccess)
+ */
+ @Override
+ public boolean handleDeleteSelection(int selectionStart, int selectionEnd, int generatedByActionId,
+ AuthorAccess authorAccess) throws InvalidEditException {
+ // Not handled.
+ return false;
+ }
+
+ /**
+ * @see ro.sync.ecss.extensions.api.AuthorSchemaAwareEditingHandler#handleJoinElements(ro.sync.ecss.extensions.api.node.AuthorNode, java.util.List, ro.sync.ecss.extensions.api.AuthorAccess)
+ */
+ @Override
+ public boolean handleJoinElements(AuthorNode targetNode, Listtrue
if the event was handled, false
otherwise.
+ *
+ * @throws InvalidEditException The event was rejected because it is invalid.
+ */
+ private boolean handleInsertionEvent(
+ int offset,
+ AuthorDocumentFragment[] fragmentsToInsert,
+ AuthorAccess authorAccess) throws InvalidEditException {
+ AuthorSchemaManager authorSchemaManager = authorAccess.getDocumentController().getAuthorSchemaManager();
+ boolean handleEvent = false;
+ try {
+ AuthorNode nodeAtInsertionOffset = authorAccess.getDocumentController().getNodeAtOffset(offset);
+ if (isElementWithNameAndNamespace(nodeAtInsertionOffset, SDF_TABLE)) {
+ // Check if the fragment is allowed as it is.
+ boolean canInsertFragments = authorSchemaManager.canInsertDocumentFragments(
+ fragmentsToInsert,
+ offset,
+ AuthorSchemaManager.VALIDATION_MODE_STRICT_FIRST_CHILD_LAX_OTHERS);
+ if (!canInsertFragments) {
+ handleEvent = handleInvalidInsertionEventInTable(
+ offset,
+ fragmentsToInsert,
+ authorAccess,
+ authorSchemaManager);
+ }
+ } else if(isElementWithNameAndNamespace(nodeAtInsertionOffset, SECTION)) {
+ // Check if the fragment is allowed as it is.
+ boolean canInsertFragments = authorSchemaManager.canInsertDocumentFragments(
+ fragmentsToInsert,
+ offset,
+ AuthorSchemaManager.VALIDATION_MODE_STRICT_FIRST_CHILD_LAX_OTHERS);
+ if (!canInsertFragments) {
+ // Insertion in 'section' element
+ handleEvent = handleInvalidInsertionEventInSect(
+ offset,
+ fragmentsToInsert,
+ authorAccess,
+ authorSchemaManager);
+ }
+ }
+ } catch (BadLocationException e) {
+ throw new InvalidEditException(e.getMessage(), "Invalid typing event: " + e.getMessage(), e, false);
+ } catch (AuthorOperationException e) {
+ throw new InvalidEditException(e.getMessage(), "Invalid typing event: " + e.getMessage(), e, false);
+ }
+ return handleEvent;
+ }
+
+ /**
+ * @return true
if the given node is an element with the given local name and from the SDF namespace.
+ */
+ protected boolean isElementWithNameAndNamespace(AuthorNode node, String elementLocalName) {
+ boolean result = false;
+ if(node.getType() == AuthorNode.NODE_TYPE_ELEMENT) {
+ AuthorElement element = (AuthorElement) node;
+ result = elementLocalName.equals(element.getLocalName()) && element.getNamespace().equals(SDF_NAMESPACE);
+ }
+ return result;
+ }
+
+ /**
+ * Try to handle invalid insertion events in a SDF 'table'.
+ * A row element will be inserted with a new cell in which the fragments will be inserted.
+ *
+ * @param offset Offset where the insertion event occurred.
+ * @param fragmentsToInsert Fragments that must be inserted at the given offset.
+ * @param authorAccess Author access.
+ * @return true
if the event was handled, false
otherwise.
+ */
+ private boolean handleInvalidInsertionEventInTable(
+ int offset,
+ AuthorDocumentFragment[] fragmentsToInsert,
+ AuthorAccess authorAccess,
+ AuthorSchemaManager authorSchemaManager) throws BadLocationException, AuthorOperationException {
+ boolean handleEvent = false;
+ // Typing/paste inside a SDF table. We will try to wrap the fragment into a new cell and insert it inside a new row.
+ WhatElementsCanGoHereContext context = authorSchemaManager.createWhatElementsCanGoHereContext(offset);
+ StringBuilder xmlFragment = new StringBuilder("<");
+ xmlFragment.append(SDF_TABLE_ROW);
+ if (SDF_NAMESPACE != null && SDF_NAMESPACE.length() != 0) {
+ xmlFragment.append(" xmlns=\"").append(SDF_NAMESPACE).append("\"");
+ }
+ xmlFragment.append("/>");
+
+ // Check if a row can be inserted at the current offset.
+ boolean canInsertRow = authorSchemaManager.canInsertDocumentFragments(
+ new AuthorDocumentFragment[] {authorAccess.getDocumentController().createNewDocumentFragmentInContext(xmlFragment.toString(), offset)},
+ context,
+ AuthorSchemaManager.VALIDATION_MODE_STRICT_FIRST_CHILD_LAX_OTHERS);
+
+ // Derive the context by adding a new row element with a cell.
+ if (canInsertRow) {
+ pushContextElement(context, SDF_TABLE_ROW);
+ pushContextElement(context, SDF_TABLE_CELL);
+
+ // Test if fragments can be inserted in the new context.
+ if (authorSchemaManager.canInsertDocumentFragments(
+ fragmentsToInsert,
+ context,
+ AuthorSchemaManager.VALIDATION_MODE_STRICT_FIRST_CHILD_LAX_OTHERS)) {
+
+ // Insert a new row with a cell.
+ xmlFragment = new StringBuilder("<");
+ xmlFragment.append(SDF_TABLE_ROW);
+
+ if (SDF_NAMESPACE != null && SDF_NAMESPACE.length() != 0) {
+ xmlFragment.append(" xmlns=\"").append(SDF_NAMESPACE).append("\"");
+ }
+ xmlFragment.append("><");
+ xmlFragment.append(SDF_TABLE_CELL);
+ xmlFragment.append("/>");
+ xmlFragment.append(SDF_TABLE_ROW);
+ xmlFragment.append(">");
+ authorAccess.getDocumentController().insertXMLFragment(xmlFragment.toString(), offset);
+
+ // Get the newly inserted cell.
+ AuthorNode newCell = authorAccess.getDocumentController().getNodeAtOffset(offset + 2);
+ for (int i = 0; i < fragmentsToInsert.length; i++) {
+ authorAccess.getDocumentController().insertFragment(newCell.getEndOffset(), fragmentsToInsert[i]);
+ }
+
+ handleEvent = true;
+ }
+ }
+ return handleEvent;
+ }
+
+ /**
+ * Derive the given context by adding the specified element.
+ */
+ protected void pushContextElement(WhatElementsCanGoHereContext context, String elementName) {
+ ContextElement contextElement = new ContextElement();
+ contextElement.setQName(elementName);
+ contextElement.setNamespace(SDF_NAMESPACE);
+ context.pushContextElement(contextElement, null);
+ }
+
+ /**
+ * Try to handle invalid insertion events in 'section'.
+ * The solution is to insert the fragmentsToInsert
into a 'title' element if the sect element is empty or
+ * into a 'para' element if the sect already contains a 'title'.
+ *
+ * @param offset Offset where the insertion event occurred.
+ * @param fragmentsToInsert Fragments that must be inserted at the given offset.
+ * @param authorAccess Author access.
+ * @return true
if the event was handled, false
otherwise.
+ */
+ private boolean handleInvalidInsertionEventInSect(int offset, AuthorDocumentFragment[] fragmentsToInsert, AuthorAccess authorAccess,
+ AuthorSchemaManager authorSchemaManager) throws BadLocationException, AuthorOperationException {
+ boolean handleEvent = false;
+ // Typing/paste inside an section.
+ AuthorElement sectionElement = (AuthorElement) authorAccess.getDocumentController().getNodeAtOffset(offset);
+
+ if (sectionElement.getStartOffset() + 1 == sectionElement.getEndOffset()) {
+ // Empty section element
+ WhatElementsCanGoHereContext context = authorSchemaManager.createWhatElementsCanGoHereContext(offset);
+ // Derive the context by adding a title.
+ pushContextElement(context, TITLE);
+
+ // Test if fragments can be inserted in 'title' element
+ if (authorSchemaManager.canInsertDocumentFragments(
+ fragmentsToInsert,
+ context,
+ AuthorSchemaManager.VALIDATION_MODE_STRICT_FIRST_CHILD_LAX_OTHERS)) {
+ // Create a title structure and insert fragments inside
+ StringBuilder xmlFragment = new StringBuilder("<").append(TITLE);
+ if (SDF_NAMESPACE != null && SDF_NAMESPACE.length() != 0) {
+ xmlFragment.append(" xmlns=\"").append(SDF_NAMESPACE).append("\"");
+ }
+ xmlFragment.append(">").append("").append(TITLE).append(">");
+ // Insert title
+ authorAccess.getDocumentController().insertXMLFragment(xmlFragment.toString(), offset);
+
+ // Insert fragments
+ AuthorNode newParaNode = authorAccess.getDocumentController().getNodeAtOffset(offset + 1);
+ for (int i = 0; i < fragmentsToInsert.length; i++) {
+ authorAccess.getDocumentController().insertFragment(newParaNode.getEndOffset(), fragmentsToInsert[i]);
+ }
+ handleEvent = true;
+ }
+ } else {
+ // Check if there is just a title.
+ Listtable
element.
+ */
+ public void init(AuthorElement table) {
+ // Nothing to do.
+ }
+
+ public String getDescription() {
+ return "Implementation for the Simple Documentation Framework table layout.";
+ }
+}
\ No newline at end of file
diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/TableColumnWidthProvider.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/TableColumnWidthProvider.java
new file mode 100644
index 0000000..f0b5d1d
--- /dev/null
+++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/TableColumnWidthProvider.java
@@ -0,0 +1,221 @@
+package simple.documentation.framework.extensions;
+import java.util.ArrayList;
+import java.util.List;
+
+import ro.sync.ecss.extensions.api.AuthorDocumentController;
+import ro.sync.ecss.extensions.api.AuthorOperationException;
+import ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider;
+import ro.sync.ecss.extensions.api.WidthRepresentation;
+import ro.sync.ecss.extensions.api.node.AttrValue;
+import ro.sync.ecss.extensions.api.node.AuthorElement;
+
+/**
+ * Simple Documentation Framework table column width provider.
+ *
+ */
+public class TableColumnWidthProvider implements AuthorTableColumnWidthProvider {
+
+ /**
+ * Cols start offset
+ */
+ private int colsStartOffset;
+
+ /**
+ * Cols end offset
+ */
+ private int colsEndOffset;
+
+ /**
+ * Column widths specifications
+ */
+ private ListTrue
if the strict mode is activated.
+ */
+ private boolean isStrictModeActivated() {
+ String strictMode = authorAccess.getOptionsStorage().getOption("strictMode", "false");
+ return "true".equals(strictMode);
+ }
+
+ /**
+ * Insert node filter.
+ */
+ @Override
+ public boolean insertNode(AuthorDocumentFilterBypass filterBypass,
+ int caretOffset, AuthorNode element) {
+ // Restrict the insertion of the "title" element if the parent element already contains a
+ // title element.
+ if (isStrictModeActivated()) {
+ String restrict = "title";
+ if(element instanceof AuthorElement) {
+ String elementName = ((AuthorElement) element).getLocalName();
+ if (restrict.equals(elementName)) {
+ try {
+ AuthorNode nodeAtOffset = authorAccess.getDocumentController().getNodeAtOffset(caretOffset);
+ if (nodeAtOffset != null && nodeAtOffset instanceof AuthorElement) {
+ AuthorElement[] elements = ((AuthorElement) nodeAtOffset).getElementsByLocalName(restrict);
+ if (elements != null && elements.length > 0) {
+ AuthorElement titleChild = elements[0];
+ if (titleChild != null) {
+ authorAccess.getWorkspaceAccess().showInformationMessage("Title already added.");
+ return false;
+ }
+ }
+ }
+ } catch (BadLocationException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ return super.insertNode(filterBypass, caretOffset, element);
+ }
+
+ /**
+ * Insert text filter.
+ */
+ @Override
+ public void insertText(AuthorDocumentFilterBypass filterBypass, int caretOffset,
+ String toInsert) {
+ super.insertText(filterBypass, caretOffset, toInsert);
+ // If the strict mode is activated and the element where the text is inserted is the "content"
+ // element then surround the inserted text into a "para" element.
+ if (isStrictModeActivated()) {
+ try {
+ AuthorNode nodeAtOffset = authorAccess.getDocumentController().getNodeAtOffset(caretOffset);
+ if (nodeAtOffset != null && nodeAtOffset instanceof AuthorElement) {
+ if ("content".equals(((AuthorElement)nodeAtOffset).getLocalName())) {
+ try {
+ filterBypass.surroundInFragment(""); + fragmentBuffer.append( + xmlEscape(metaData.getColumnName(i))); + fragmentBuffer.append(" | "); + } + fragmentBuffer.append("
"); + fragmentBuffer.append( + xmlEscape(resultSet.getObject(i))); + fragmentBuffer.append(" | "); + } + fragmentBuffer.append("
true
if modal.
+ * @param highlights List of highlights to be edited.
+ * @param auhorAccess The Author access
+ */
+ public EditHighlightsDialog(
+ JFrame parentFrame,
+ String title,
+ boolean modal,
+ final List"); + } + tableXMLFragment.append(" |
null
then the user canceled the table insertion.
+ */
+ public TableInfo showDialog() {
+ // Reset components to default values
+ titleTextField.setEditable(true);
+ titleTextField.setText("");
+ titleCheckbox.setSelected(true);
+
+ tableBgColorButton.setEnabled(false);
+ tableBgColorButton.setBackground(tableBgColorCheckbox.getBackground());
+ tableBgColorCheckbox.setSelected(false);
+
+ // Set the default number of rows and columns
+ rowsSpinner.setValue(new Integer(3));
+ columnsSpinner.setValue(new Integer(2));
+
+ // Request focus in title field
+ titleTextField.requestFocus();
+
+ super.setVisible(true);
+
+ TableInfo tableInfo = null;
+ if(getResult() == RESULT_OK) {
+ // Title
+ String title = null;
+ if(titleCheckbox.isSelected()) {
+ title = titleTextField.getText();
+ title = ro.sync.basic.xml.BasicXmlUtil.escape(title);
+ }
+ // Table background color
+ Color tableBgColor = null;
+ if(tableBgColorCheckbox.isSelected()) {
+ tableBgColor = tableBgColorButton.getBackground();
+ }
+ int rowsNumber = ((Integer)rowsSpinner.getValue()).intValue();
+ int columnsNumber = ((Integer)columnsSpinner.getValue()).intValue();
+
+ tableInfo =
+ new TableInfo(
+ title,
+ rowsNumber,
+ columnsNumber,
+ tableBgColor);
+ } else {
+ // Cancel was pressed
+ }
+ return tableInfo;
+ }
+}
\ No newline at end of file
diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/ui/SDFPopupWindow.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/ui/SDFPopupWindow.java
new file mode 100644
index 0000000..51bc127
--- /dev/null
+++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/ui/SDFPopupWindow.java
@@ -0,0 +1,110 @@
+package simple.documentation.framework.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.IllegalComponentStateException;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.swing.BorderFactory;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JWindow;
+
+import ro.sync.ecss.extensions.api.AuthorAccess;
+import ro.sync.exml.view.graphics.Point;
+
+/**
+ * Popup window used to display Simple Documentation Framework specific information.
+ *
+ */
+@SuppressWarnings("serial")
+public class SDFPopupWindow extends JWindow {
+
+ /**
+ * Text area used to display useful informations.
+ */
+ private JTextArea infoTextArea;
+
+ /**
+ * Access to the author specific functions.
+ */
+ AuthorAccess authorAccess;
+
+ /**
+ * The display time of the popup window (seconds).
+ */
+ private int timeToDisplay;
+
+ /**
+ *
+ * @param access Author access.
+ * @param infoDescription Description.
+ */
+ public SDFPopupWindow(AuthorAccess access, String infoDescription) {
+ super((JFrame) access.getWorkspaceAccess().getParentFrame());
+ this.authorAccess = access;
+
+ // Create information text area.
+ infoTextArea = new JTextArea();
+ infoTextArea.setLineWrap(true);
+ infoTextArea.setWrapStyleWord(true);
+ infoTextArea.setEditable(false);
+ infoTextArea.setFocusable(false);
+
+ JPanel mainContent = new JPanel(new BorderLayout());
+ if (infoDescription != null) {
+ mainContent.add(new JLabel(infoDescription), BorderLayout.NORTH);
+ }
+ mainContent.setFocusable(false);
+ mainContent.add(infoTextArea, BorderLayout.SOUTH);
+ mainContent.setBorder(BorderFactory.createLineBorder(Color.black));
+ getContentPane().add(mainContent);
+ setVisible(false);
+ }
+
+ /**
+ * Set the time to display this popup window.
+ *
+ * @param timeToDisplay The display time in seconds.
+ */
+ public void setTimeToDisplay(int timeToDisplay) {
+ this.timeToDisplay = timeToDisplay;
+ }
+
+ /**
+ * Display the specified text information.
+ *
+ * @param text The text to be displayed in the popup window.
+ * @param relX The "x" coordinate relative to the viewport.
+ * @param relY The "y" coordinate relative to the viewport.
+ * @param delta The translation point where the popup should be displayed from the given (x, y) point.
+ */
+ public void display(String text, int relX, int relY, int delta) {
+ // Transform the given relative coordinates into absolute coordinates.
+ try {
+ Point translatedPoint = authorAccess.getEditorAccess().getLocationOnScreenAsPoint(relX, relY);
+ setVisible(false);
+ infoTextArea.setText(text);
+ setLocation(translatedPoint.x + delta, translatedPoint.y + delta);
+ pack();
+ // Show the information popup window
+ setVisible(true);
+
+ // Hide the window when the given display time is finished.
+ if (timeToDisplay > 0) {
+ Timer timer = new Timer();
+ timer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ setVisible(false);
+ }
+ }, timeToDisplay * 1000);
+ }
+ } catch (IllegalComponentStateException e) {
+ // Do nothing
+ }
+ }
+}
diff --git a/oxygen/js-debugger-importer/templates/article.xml b/oxygen/js-debugger-importer/templates/article.xml
new file mode 100644
index 0000000..a40fa2a
--- /dev/null
+++ b/oxygen/js-debugger-importer/templates/article.xml
@@ -0,0 +1,11 @@
+
+Company | +Date | +
+ | + |
+
+
+