From 122c73ef1fc4061220ff50cff01d953b41ad2d74 Mon Sep 17 00:00:00 2001 From: Eric van der Vlist Date: Sun, 25 Apr 2021 10:49:16 +0200 Subject: [PATCH] Copying directories --- oxygen/js-debugger-importer/README.md | 101 ++ oxygen/js-debugger-importer/catalog.xml | 9 + oxygen/js-debugger-importer/commons.js | 17 + oxygen/js-debugger-importer/css/sdf.css | 145 ++ oxygen/js-debugger-importer/debugger.jpg | Bin 0 -> 39182 bytes oxygen/js-debugger-importer/debugger2.jpg | Bin 0 -> 161551 bytes .../icons/insertImage16.JPG | Bin 0 -> 777 bytes .../icons/insertImage20.JPG | Bin 0 -> 927 bytes .../icons/insertSection16.JPG | Bin 0 -> 762 bytes .../icons/insertSection20.JPG | Bin 0 -> 826 bytes .../icons/insertTable16.JPG | Bin 0 -> 811 bytes .../icons/insertTable20.JPG | Bin 0 -> 928 bytes .../icons/refreshCSS16.JPG | Bin 0 -> 800 bytes .../icons/refreshCSS20.JPG | Bin 0 -> 946 bytes .../icons/strictMode16.JPG | Bin 0 -> 766 bytes .../icons/strictMode20.JPG | Bin 0 -> 870 bytes .../js-debugger-importer.xpr | 10 + .../resources/countries.txt | 1 + oxygen/js-debugger-importer/schema/abs.xsd | 6 + oxygen/js-debugger-importer/schema/sdf.xsd | 112 ++ oxygen/js-debugger-importer/sdf.framework | 1338 +++++++++++++++++ oxygen/js-debugger-importer/sdf.jar | Bin 0 -> 110627 bytes oxygen/js-debugger-importer/sdf_sample.xml | 91 ++ .../framework/AuthorAccessProvider.java | 16 + .../documentation/framework/CustomRule.java | 44 + .../documentation/framework/SDFElement.java | 552 +++++++ .../framework/SDFExtensionsBundle.java | 173 +++ .../framework/SDFLinkTextResolver.java | 72 + .../callouts/CalloutsRenderingProvider.java | 95 ++ ...horPersistentHighlightActionsProvider.java | 63 + .../extensions/SDFAttributesValueEditor.java | 69 + .../SDFAuthorBreadCrumbCustomizer.java | 60 + .../SDFAuthorExtensionStateListener.java | 374 +++++ .../SDFAuthorOutlineCustomizer.java | 158 ++ .../SDFExternalObjectInsertionHandler.java | 72 + .../extensions/SDFReferencesResolver.java | 199 +++ .../SDFSchemaAwareEditingHandler.java | 353 +++++ .../extensions/SDFSchemaManagerFilter.java | 142 ++ .../framework/extensions/SDFStylesFilter.java | 139 ++ .../extensions/TableCellSpanProvider.java | 74 + .../extensions/TableColumnWidthProvider.java | 221 +++ .../framework/filters/SDFDocumentFilter.java | 104 ++ .../listeners/SDFAuthorCaretListener.java | 76 + .../listeners/SDFAuthorListener.java | 130 ++ .../listeners/SDFAuthorMouseListener.java | 62 + .../ExtractNodeToFileOperation.java | 76 + .../operations/InsertElementOperation.java | 127 ++ .../operations/InsertImageOperation.java | 213 +++ .../framework/operations/OpenInNewEditor.java | 39 + .../operations/QueryDatabaseOperation.java | 196 +++ .../operations/SDFRefreshCSSOperation.java | 38 + .../SDFShowFileStatusOperation.java | 45 + .../operations/SDFStrictModeOperation.java | 54 + .../SelectNodesInOutlinerOperation.java | 103 ++ .../operations/TrasformOperation.java | 82 + .../highlight/AddHighlightOperation.java | 71 + .../highlight/ChangeReviewAuthorDialog.java | 55 + .../ChangeReviewAuthorOperation.java | 51 + .../highlight/EditHighlightsDialog.java | 190 +++ .../highlight/EditHighlightsOperation.java | 79 + .../highlight/HighlightProperties.java | 19 + .../RemoveAllHighlightsOperation.java | 41 + .../highlight/ReviewParaOperation.java | 108 ++ .../table/InsertTableOperation.java | 89 ++ .../table/TableCustomizerDialog.java | 339 +++++ .../framework/ui/SDFPopupWindow.java | 110 ++ .../templates/article.xml | 11 + .../js-debugger-importer/templates/book.xml | 22 + oxygen/js-debugger-importer/test.js | 34 + oxygen/js-debugger-importer/xsl/sdf.xsl | 68 + 70 files changed, 7338 insertions(+) create mode 100644 oxygen/js-debugger-importer/README.md create mode 100644 oxygen/js-debugger-importer/catalog.xml create mode 100644 oxygen/js-debugger-importer/commons.js create mode 100644 oxygen/js-debugger-importer/css/sdf.css create mode 100644 oxygen/js-debugger-importer/debugger.jpg create mode 100644 oxygen/js-debugger-importer/debugger2.jpg create mode 100644 oxygen/js-debugger-importer/icons/insertImage16.JPG create mode 100644 oxygen/js-debugger-importer/icons/insertImage20.JPG create mode 100644 oxygen/js-debugger-importer/icons/insertSection16.JPG create mode 100644 oxygen/js-debugger-importer/icons/insertSection20.JPG create mode 100644 oxygen/js-debugger-importer/icons/insertTable16.JPG create mode 100644 oxygen/js-debugger-importer/icons/insertTable20.JPG create mode 100644 oxygen/js-debugger-importer/icons/refreshCSS16.JPG create mode 100644 oxygen/js-debugger-importer/icons/refreshCSS20.JPG create mode 100644 oxygen/js-debugger-importer/icons/strictMode16.JPG create mode 100644 oxygen/js-debugger-importer/icons/strictMode20.JPG create mode 100644 oxygen/js-debugger-importer/js-debugger-importer.xpr create mode 100644 oxygen/js-debugger-importer/resources/countries.txt create mode 100644 oxygen/js-debugger-importer/schema/abs.xsd create mode 100644 oxygen/js-debugger-importer/schema/sdf.xsd create mode 100644 oxygen/js-debugger-importer/sdf.framework create mode 100644 oxygen/js-debugger-importer/sdf.jar create mode 100644 oxygen/js-debugger-importer/sdf_sample.xml create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/AuthorAccessProvider.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/CustomRule.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFElement.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFExtensionsBundle.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFLinkTextResolver.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/callouts/CalloutsRenderingProvider.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/callouts/SDFAuthorPersistentHighlightActionsProvider.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAttributesValueEditor.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorBreadCrumbCustomizer.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorExtensionStateListener.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorOutlineCustomizer.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFExternalObjectInsertionHandler.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFReferencesResolver.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFSchemaAwareEditingHandler.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFSchemaManagerFilter.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFStylesFilter.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/TableCellSpanProvider.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/TableColumnWidthProvider.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/filters/SDFDocumentFilter.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorCaretListener.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorListener.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorMouseListener.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/ExtractNodeToFileOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/InsertElementOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/InsertImageOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/OpenInNewEditor.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/QueryDatabaseOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFRefreshCSSOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFShowFileStatusOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFStrictModeOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SelectNodesInOutlinerOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/TrasformOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/AddHighlightOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ChangeReviewAuthorDialog.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ChangeReviewAuthorOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/EditHighlightsDialog.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/EditHighlightsOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/HighlightProperties.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/RemoveAllHighlightsOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ReviewParaOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/table/InsertTableOperation.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/table/TableCustomizerDialog.java create mode 100644 oxygen/js-debugger-importer/src-java/simple/documentation/framework/ui/SDFPopupWindow.java create mode 100644 oxygen/js-debugger-importer/templates/article.xml create mode 100644 oxygen/js-debugger-importer/templates/book.xml create mode 100644 oxygen/js-debugger-importer/test.js create mode 100644 oxygen/js-debugger-importer/xsl/sdf.xsl diff --git a/oxygen/js-debugger-importer/README.md b/oxygen/js-debugger-importer/README.md new file mode 100644 index 0000000..bcc529c --- /dev/null +++ b/oxygen/js-debugger-importer/README.md @@ -0,0 +1,101 @@ +# Opening a JavaScript debugger within Oxygen [JS Operations](https://www.oxygenxml.com/doc/versions/23.1/ug-editor/topics/dg-default-author-operations.html#dg-default-author-operations__jsoperation) + +Even though its authors state that this operation "[can be used to execute small pieces of Javascript code](https://github.com/oxygenxml/javascript-sample-operations)", +all the Oxygen and Java public APIs are exposed and this operation can be used for fairly complex tasks. + +The main limitation is then the lack of a debugger and relying on logs rapidly becomes very tedious to develop complex code. + +The good news is that Oxygen uses Mozilla's [Rhino JavaScript engine](https://en.wikipedia.org/wiki/Rhino_(JavaScript_engine)) and that this engine comes with a +[debugger](https://www-archive.mozilla.org/rhino/debugger.html). + +This rambling proposes a way to launch the debugger from a JS Operation. + +## Installation + +To do so, add this function to your commons.js file: + +```javascript +startDebugger = function () { + + var runnable = { + run: function () { + main.dispose(); + } + } + + + var context = Packages.org.mozilla.javascript.Context.getCurrentContext(); // Within the current context... + var contextFactory = context.getFactory(); + var scope = Packages.org.mozilla.javascript.tools.shell.Environment(runnable.__parent__); // and the scope of the runnable variable's parent ... + var main = Packages.org.mozilla.javascript.tools. debugger.Main.mainEmbedded(contextFactory, scope, 'Debugger'); // start a debugging session ... + main.setExitAction(java.lang.Runnable(runnable)); // , clean the resources at exit time... + main.setVisible(true); // and make it visible/ + +} +``` + +And use it in the script parameter of the JS operation: +```javascript +doOperation = startDebugger; +``` + +To call the action which uses this operation, you can attach it to a menu or tool icon or just define a shortkey and you're done ! + +Call this action and you'll pop up a nice vintage debugger : +![debugger.jpg](debugger.jpg) + +Use the File menu to open or run the file to debug (such as [test.js]): +![debugger2.jpg](debugger2.jpg) + +There are a few things to know before using it, though... + +## Limitations + +### Scope + +I haven't found a way to simply grab the current scope object in JavaScript and the closest method I have found is: +```javascript +Packages.org.mozilla.javascript.tools.shell.Environment(runnable.__parent__) +``` + +This creates a scope with everything in the runnable's parent's scope augmented with the environment variables with may not be present in the current scope. + + +All the other methods I have tried gave scopes which were, on the contrary, reduced compared to the current scope and lacking, for instance, the authorAcces object +without which you can't interact with Oxygen. + +### Functions seen as objects + +Just try it by yourself in the "evaluate" window: +```javascript +function a() {} + +b = function() {} +``` +"a" is seen as an object and not as a function, meaning that you can't call it. "b" is, correctly, seen as a function. + +### Strict behavior on instanciation. + +The word "new" is mandatory when instanciating a "class" (which is not the case when a JS operation script is run out of the debugger): + +```javascript +aclass = function () { + this.setFoo(1); + return this; +} + +aclass.prototype.setFoo = function (v) { + this.foo = v; +} + +anObject = new aclass() ; // works as expected + +anobject = aclass(); // fails with a message saying that there is no setFoo function in the object + +``` + +# Framework + +This directory includes the Oxygen sample framework on which ou can test the debugger but it should work on any framework. + + diff --git a/oxygen/js-debugger-importer/catalog.xml b/oxygen/js-debugger-importer/catalog.xml new file mode 100644 index 0000000..329f379 --- /dev/null +++ b/oxygen/js-debugger-importer/catalog.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/oxygen/js-debugger-importer/commons.js b/oxygen/js-debugger-importer/commons.js new file mode 100644 index 0000000..be71a9a --- /dev/null +++ b/oxygen/js-debugger-importer/commons.js @@ -0,0 +1,17 @@ +startDebugger = function () { + + var runnable = { + run: function () { + main.dispose(); + } + } + + + var context = Packages.org.mozilla.javascript.Context.getCurrentContext(); // Within the current context... + var contextFactory = context.getFactory(); + var scope = Packages.org.mozilla.javascript.tools.shell.Environment(runnable.__parent__); // and the scope of the runnable variable's parent ... + var main = Packages.org.mozilla.javascript.tools. debugger.Main.mainEmbedded(contextFactory, scope, 'Debugger'); // start a debugging session ... + main.setExitAction(java.lang.Runnable(runnable)); // , clean the resources at exit time... + main.setVisible(true); // and make it visible/ + +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/css/sdf.css b/oxygen/js-debugger-importer/css/sdf.css new file mode 100644 index 0000000..c1b1541 --- /dev/null +++ b/oxygen/js-debugger-importer/css/sdf.css @@ -0,0 +1,145 @@ +/* Element from another namespace */ +@namespace abs "http://www.oxygenxml.com/sample/documentation/abstracts"; + +abs|def{ + font-family:monospace; + font-size:smaller; +} +abs|def:before{ + content:"Definition:"; + color:gray; +} + +/* Vertical flow */ +book, +section, +para, +title, +image, +ref { + display:block; +} + +/* Horizontal flow */ +b,i { + display:inline; +} + +section{ + margin-left:1em; + margin-top:1em; +} + +section{ + -oxy-foldable:true; + -oxy-not-foldable-child: title; +} + +link[href]:before{ + display:inline; + link:attr(href); + content: "Click to open: " attr(href); +} + +link:before { + content:oxy_link-text(); +} + +/* Title rendering*/ +title{ + font-size: 2.4em; + font-weight:bold; +} + +* * title{ + font-size: 2.0em; +} +* * * title{ + font-size: 1.6em; +} +* * * * title{ + font-size: 1.2em; +} + +book, +article{ + counter-reset:sect; +} +book > section, +article > section{ + counter-increment:sect; +} +book > section > title:before, +article > section > title:before{ + content: "Section: " counter(sect) " "; +} + +/* Inlines rendering*/ +b { + font-weight:bold; +} + +i { + font-style:italic; +} + +/*Table rendering */ +table{ + display:table; + border:1px solid navy; + margin:1em; + max-width:1000px; + min-width:150px; +} + +table[width]{ + width:attr(width, length); +} + +table[bgcolor], +tr[bgcolor], +td[bgcolor]{ + background-color:attr(bgcolor); + color:inherit; +} + +tr, header{ + display:table-row; +} + +customcol { + text-align:left; + display:block; + color:#444444; + background-color:inherit; + margin:0.2em; + padding:2px; + font-family:monospace; + font-size:small; +} + +header{ + background-color: silver; + color:inherit +} + +td{ + display:table-cell; + border:1px solid navy; + padding:1em; +} + +image{ + display:block; + content: attr(href, url); + margin-left:2em; +} + +author, name, country { + display:block; + margin-left:20px; +} + +name:before { + content: oxy_label(text, "Author: ", width, 100px, color, gray); +} diff --git a/oxygen/js-debugger-importer/debugger.jpg b/oxygen/js-debugger-importer/debugger.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f93e898ce908c578f2ff44510b469768aa40745 GIT binary patch literal 39182 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 tx8UhVXv&`cFdS;PFc-St$Sp1^{57e}Ma0KmtHQ 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 M+?6-HpCj&1jzO5 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 z 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
    {+u(gJRb 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 literal 0 HcmV?d00001 diff --git a/oxygen/js-debugger-importer/icons/insertImage16.JPG b/oxygen/js-debugger-importer/icons/insertImage16.JPG new file mode 100644 index 0000000000000000000000000000000000000000..8055e8f81ed1059a10917b3f0fa865d375273bd5 GIT binary patch literal 777 zcmex=Hq-)3-T;9z58XJh4H zXJ_Z+|EI`$@KzRlhK~^C}Lq|5@z(jVX zLJ_0Ji3>TDoi-j64Z8S2#W<;`iIYoATtZSxRZU$(Q_IBE%-q7#%Gt%$&E3P(D>x)H zEIcAIDmf)JEj=SMtGJ}Jth}PKs=1}Lt-YhOYtrN?Q>RUzF>}_U#Y>hhTfSoDs!f}> zY~8kf$Ie}c4j(ys?D&b3r!HN-a`oEv8#iw~eDwIq(`V0LynOZX)8{W=zkUDl^B2fp zj10^WZ^3TY#v@lcIY~ c8v>`KR?mJ^C^$!1Vs+HreYN^O=KsG50M?feod5s; literal 0 HcmV?d00001 diff --git a/oxygen/js-debugger-importer/icons/insertImage20.JPG b/oxygen/js-debugger-importer/icons/insertImage20.JPG new file mode 100644 index 0000000000000000000000000000000000000000..e3b1131662648b5ae3003adb642c265590cc2ec8 GIT binary patch literal 927 zcmex=Hq-)3-T;9z58XJh4H zXJ_Z+|EI`$@KzRlhK~^C}Lq|5@z(jVX zLJ_0Ji3>TDoi-j64Z8S2#W<;`iIYoATtZSxRZU$(Q_IBE%-q7#%Gt%$&E3P(D>x)H zEIcAIDmf)JEj=SMtGJ}Jth}PKs=1}Lt-YhOYtrN?Q>RUzF>}_U#Y>hhTfSoDs!f}> zY~8kf$Ie}c4j(ys?D&b3r!HN-a`oEv8#iw~eDwIq(`V0LynOZX)8{W=zkUDl^B2fp zj10^WZ^3| zTrpW|9P&vw>61%g?L4)E858?;mV8xTxvu$Pe!ppL{O{<0LfX5#?`xm@WOp|CSlwU!pEXAHAzqd7->3 zwR^3du9t<+nb%uVa+LSk7QYN_Z!2m4&(ObGL*MXw-Blsa&DSMm(tmMjEL`#>Iny*P f%T=VnX~JPCcabbnK{io`2Mp|vt|Gyb|8D{SwfJBF literal 0 HcmV?d00001 diff --git a/oxygen/js-debugger-importer/icons/insertSection16.JPG b/oxygen/js-debugger-importer/icons/insertSection16.JPG new file mode 100644 index 0000000000000000000000000000000000000000..6f8c020c7016c83ffa81f0aa4fcd869f2fbc7768 GIT binary patch literal 762 zcmex=Hq-)3-T;9z58XJh4H zXJ_Z+|EI`$@KzRlhK~^C}Lq|5@z(jVX zLJ_0Ji3>TDoi-j64Z8S2#W<;`iIYoATtZSxRZU$(Q_IBE%-q7#%Gt%$&E3P(D>x)H zEIcAIDmf)JEj=SMtGJ}Jth}PKs=1}Lt-YhOYtrN?Q>RUzF>}_U#Y>hhTfSoDs!f}> zY~8kf$Ie}c4j(ys?D&b3r!HN-a`oEv8#iw~eDwIq(`V0LynOZX)8{W=zkUDl^B2fp zj10^WZ^3mWRhlc#=+1-8*ceUZ`Zq1Zqxq9xWC8#h3dlp4EKNT L|8bR}{{Kw?=}-%0 literal 0 HcmV?d00001 diff --git a/oxygen/js-debugger-importer/icons/insertSection20.JPG b/oxygen/js-debugger-importer/icons/insertSection20.JPG new file mode 100644 index 0000000000000000000000000000000000000000..5dd7bb5c90079cd5bb288918732ec83f46355877 GIT binary patch literal 826 zcmex=Hq-)3-T;9z58XJh4H zXJ_Z+|EI`$@KzRlhK~^C}Lq|5@z(jVX zLJ_0Ji3>TDoi-j64Z8S2#W<;`iIYoATtZSxRZU$(Q_IBE%-q7#%Gt%$&E3P(D>x)H zEIcAIDmf)JEj=SMtGJ}Jth}PKs=1}Lt-YhOYtrN?Q>RUzF>}_U#Y>hhTfSoDs!f}> zY~8kf$Ie}c4j(ys?D&b3r!HN-a`oEv8#iw~eDwIq(`V0LynOZX)8{W=zkUDl^B2fp zj10^WZ^3@h+8y8apFw=VkJdGJU*;~_+w$S|-=)%TnNmx6M4mql;?UXg;Q726&(Hl+t5|jZ z;6CHoZX15oK6K0$G2G=_xs=WLUCgwYTxrKs-=Ff^wz19pcs$~w&HXp?c`AYqpF2MD zn>TxRopI0G3F(rywZ06sVJ|pexnDf-FC_d-`nTSXmH!!LHq-)3-T;9z58XJh4H zXJ_Z+|EI`$@KzRlhK~^C}Lq|5@z(jVX zLJ_0Ji3>TDoi-j64Z8S2#W<;`iIYoATtZSxRZU$(Q_IBE%-q7#%Gt%$&E3P(D>x)H zEIcAIDmf)JEj=SMtGJ}Jth}PKs=1}Lt-YhOYtrN?Q>RUzF>}_U#Y>hhTfSoDs!f}> zY~8kf$Ie}c4j(ys?D&b3r!HN-a`oEv8#iw~eDwIq(`V0LynOZX)8{W=zkUDl^B2fp zj10^WZ^3*=T_(52a_jpCO(|&s;j&9Kf^=Wk22xR(cb6H9!Ey%UXtI=x#{EImCXkI>rWin MZ>j!l0ssG-03+ZdwEzGB literal 0 HcmV?d00001 diff --git a/oxygen/js-debugger-importer/icons/insertTable20.JPG b/oxygen/js-debugger-importer/icons/insertTable20.JPG new file mode 100644 index 0000000000000000000000000000000000000000..56a0e95edf42bb25e700c88d02c998e86e0ecf3d GIT binary patch literal 928 zcmex=Hq-)3-T;9z58XJh4H zXJ_Z+|EI`$@KzRlhK~^C}Lq|5@z(jVX zLJ_0Ji3>TDoi-j64Z8S2#W<;`iIYoATtZSxRZU$(Q_IBE%-q7#%Gt%$&E3P(D>x)H zEIcAIDmf)JEj=SMtGJ}Jth}PKs=1}Lt-YhOYtrN?Q>RUzF>}_U#Y>hhTfSoDs!f}> zY~8kf$Ie}c4j(ys?D&b3r!HN-a`oEv8#iw~eDwIq(`V0LynOZX)8{W=zkUDl^B2fp zj10^WZ^3Bg~j;AiyJ(6o^E@^Do`c41cW0_4odCymhKD(|be8eow`%%AS?X+mm zrxUifH%zXwQ7l`3V^cWaPYVm{N=eDd#|vNi7d{T#w0lb%>xVsVPt~?%M!BAS&vD3= zqi~)_-r_#X3%j;{4F97Z<+W||V##wes{)Tr)(F^_yY4~wTT7L>J1iv*K6u{1H~CQc zb*cHyCDy-B+MHg!*6v>B{0!;2i-V3cH%{{R(%Ro>|72c8_P>K+`+sR>Ea09sy={wZ z+QU3kUt!;Ua|4u4mS#=b5Hq9e?^wWzUyL56`{Vo{d{^Z%OwH~v_p literal 0 HcmV?d00001 diff --git a/oxygen/js-debugger-importer/icons/refreshCSS16.JPG b/oxygen/js-debugger-importer/icons/refreshCSS16.JPG new file mode 100644 index 0000000000000000000000000000000000000000..0cade03d0b2f8bf5b7813cbf4e55d1f9e0c4b026 GIT binary patch literal 800 zcmex=Hq-)3-T;9z58XJh4H zXJ_Z+|EI`$@KzRlhK~^C}Lq|5@z(jVX zLJ_0Ji3>TDoi-j64Z8S2#W<;`iIYoATtZSxRZU$(Q_IBE%-q7#%Gt%$&E3P(D>x)H zEIcAIDmf)JEj=SMtGJ}Jth}PKs=1}Lt-YhOYtrN?Q>RUzF>}_U#Y>hhTfSoDs!f}> zY~8kf$Ie}c4j(ys?D&b3r!HN-a`oEv8#iw~eDwIq(`V0LynOZX)8{W=zkUDl^B2fp zj10^WZ^3Hq-)3-T;9z58XJh4H zXJ_Z+|EI`$@KzRlhK~^C}Lq|5@z(jVX zLJ_0Ji3>TDoi-j64Z8S2#W<;`iIYoATtZSxRZU$(Q_IBE%-q7#%Gt%$&E3P(D>x)H zEIcAIDmf)JEj=SMtGJ}Jth}PKs=1}Lt-YhOYtrN?Q>RUzF>}_U#Y>hhTfSoDs!f}> zY~8kf$Ie}c4j(ys?D&b3r!HN-a`oEv8#iw~eDwIq(`V0LynOZX)8{W=zkUDl^B2fp zj10^WZ^3wGpjC4iGj?44hw1@jK}N$fS(rT;T zU$~;~{biBpX zW!pRte0f)OF?PbUr!lwZe)+jm-0rXU^{{Q?^(PF6}rMnOeST|r4lSw=>~TvNxu(8R<ECr+Na zbot8FYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab&A3Fhjfr_ZgbM1cClyVqsxs zVF&q(k*OSrnFU!`6%E;h90S=C3x$=88aYIqCNA7~kW<+>=!0ld(M2vX6_bamA3uRl~&9pmntuye=GzH178SMNP%*q!h; z@TB^$tG!0A19nEbEnL2INyh>KN`QWte!r@Y*ID;e~N8vR54Y&ydmVJt@RY%-onWWm`alfsSMwcL~EB X#_O|Y?@KO~u=4%-Z_j@Q=l?eW?UoO# literal 0 HcmV?d00001 diff --git a/oxygen/js-debugger-importer/icons/strictMode20.JPG b/oxygen/js-debugger-importer/icons/strictMode20.JPG new file mode 100644 index 0000000000000000000000000000000000000000..6b7cc2d2592754b5bb5adeebaa8b514ba53296bc GIT binary patch literal 870 zcmex=Hq-)3-T;9z58XJh4H zXJ_Z+|EI`$@KzRlhK~^C}Lq|5@z(jVX zLJ_0Ji3>TDoi-j64Z8S2#W<;`iIYoATtZSxRZU$(Q_IBE%-q7#%Gt%$&E3P(D>x)H zEIcAIDmf)JEj=SMtGJ}Jth}PKs=1}Lt-YhOYtrN?Q>RUzF>}_U#Y>hhTfSoDs!f}> zY~8kf$Ie}c4j(ys?D&b3r!HN-a`oEv8#iw~eDwIq(`V0LynOZX)8{W=zkUDl^B2fp zj10^WZ^3hjvq3c z_9^DD>DjYa=7nxu!))Yrr$lZ}|Cy?5^6mRn=XyssyII69O4IUvTc+kSY`Kyv>VGrk!P9QRPao%5{;XX+d;9gLn?Fu(|MJ&6 z?BbqO(KAOAcC_6yn|E^4j)HIt$%9`HO}-IkG&$(bmy8R`t<0b9zP{h@u5DhmtVm$A zTw!>?<(#eA=9{nRChgo_lh+r@vs~8dnqT{adftkn2X``~d<^{0sitMhq_2}asr+G4 XS6KMYtR+`sf-lZx6$$id{(lnyq+LWw literal 0 HcmV?d00001 diff --git a/oxygen/js-debugger-importer/js-debugger-importer.xpr b/oxygen/js-debugger-importer/js-debugger-importer.xpr new file mode 100644 index 0000000..854430f --- /dev/null +++ b/oxygen/js-debugger-importer/js-debugger-importer.xpr @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/oxygen/js-debugger-importer/resources/countries.txt b/oxygen/js-debugger-importer/resources/countries.txt new file mode 100644 index 0000000..228c8a6 --- /dev/null +++ b/oxygen/js-debugger-importer/resources/countries.txt @@ -0,0 +1 @@ +France, Spain, Great Britain \ No newline at end of file diff --git a/oxygen/js-debugger-importer/schema/abs.xsd b/oxygen/js-debugger-importer/schema/abs.xsd new file mode 100644 index 0000000..32edb55 --- /dev/null +++ b/oxygen/js-debugger-importer/schema/abs.xsd @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/oxygen/js-debugger-importer/schema/sdf.xsd b/oxygen/js-debugger-importer/schema/sdf.xsd new file mode 100644 index 0000000..2092837 --- /dev/null +++ b/oxygen/js-debugger-importer/schema/sdf.xsd @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/oxygen/js-debugger-importer/sdf.framework b/oxygen/js-debugger-importer/sdf.framework new file mode 100644 index 0000000..993b97b --- /dev/null +++ b/oxygen/js-debugger-importer/sdf.framework @@ -0,0 +1,1338 @@ + + + + + document.types + + + + + + + SDF + + + + + 2 + + + ${framework}/schema/sdf.xsd + + + + + + ${framework}/sdf.jar + ${frameworks}/docbook/docbook.jar + + + + + + + + + + + + ${framework}/css/sdf.css + + + sdf + + + false + + + + + + true + + + false + + + + + + insert_section + + + Insert section + + + Insert a section to the caret pasition. + + + ${framework}/icons/insertSection20.jpg + + + ${framework}/icons/insertSection16.jpg + + + i + + + + + + + + + local-name()='section' or local-name()='book' or local-name()='article' + + + + + fragment + <section xmlns="http://www.oxygenxml.com/sample/documentation"><title/><para/></section> + + + + + ro.sync.ecss.extensions.commons.operations.InsertFragmentOperation + + + + + + false + + + + + insert_table + + + Insert table. + + + Insert table. + + + ${framework}/icons/insertTable20.jpg + + + ${framework}/icons/insertTable16.jpg + + + t + + + + + + + + + + + + + + + simple.documentation.framework.operations.table.InsertTableOperation + + + + + + false + + + + + insert_image + + + Insert image + + + Inserts an image + + + ${framework}/icons/insertImage20.jpg + + + ${framework}/icons/insertImage16.jpg + + + i + + + + + + + + + + + + + + + simple.documentation.framework.operations.InsertImageOperation + + + + + + false + + + + + clients_report + + + Clients Report + + + Connects to the database and collects the list of clients. + + + + + + + + + r + + + + + + + + + local-name()='section' + + + + + + simple.documentation.framework.operations.QueryDatabaseOperation + + + + + + false + + + + + inser_ref + + + Insert Ref + + + Insert Ref + + + + + + + + + + + + + + + + + + + + + + + fragment + <ref location=""/> + + + + + ro.sync.ecss.extensions.commons.operations.SurroundWithFragmentOperation + + + + + + false + + + + + refresh + + + Refresh css + + + Refresh CSS + + + ${framework}/icons/refreshCSS20.jpg + + + ${framework}/icons/refreshCSS16.jpg + + + + + + + + + + + + true() + + + + + + simple.documentation.framework.operations.SDFRefreshCSSOperation + + + + + + false + + + + + show_file_status + + + Show File Status + + + Show File Status + + + + + + + + + + + + + + + + + + true() + + + + + + simple.documentation.framework.operations.SDFShowFileStatusOperation + + + + + + false + + + + + strict_mode + + + Strict Mode + + + Strict Mode On/Off + + + ${framework}/icons/strictMode20.jpg + + + ${framework}/icons/strictMode16.jpg + + + + + + + + + + + + true() + + + + + + simple.documentation.framework.operations.SDFStrictModeOperation + + + + + + false + + + + + transform + + + Transform + + + Custom Transformation using a specified xsl. + + + + + + + + + + + + + + + + + + true() + + + + + + simple.documentation.framework.operations.TrasformOperation + + + + + + false + + + + + select_children + + + Select Children + + + Select Children in Outline + + + + + + + + + + + + + + + + + + + + + + + + simple.documentation.framework.operations.SelectNodesInOutlinerOperation + + + + + + false + + + + + insert_element + + + Insert Element + + + Show a popup menu that contains the name of all elements that can be inserted at the caret offset. + + + + + + + + + + + + + + + + + + + + + + + + simple.documentation.framework.operations.InsertElementOperation + + + + + + false + + + + + extract_node + + + Extract Node + + + Save the Author node at caret in a separate document and refresh the new file path in the project + + + + + + + + + + + + + + + + + + + + + + + + simple.documentation.framework.operations.ExtractNodeToFileOperation + + + + + + false + + + + + add_highlight + + + Add highlight + + + Highlight element at the caret position + + + + + + + + + + + + + + + + + + + + + + + + simple.documentation.framework.operations.highlight.AddHighlightOperation + + + + + + false + + + + + edit_highlights + + + Edit Highlights + + + Edit all highlights from caret position + + + + + + + + + + + + + + + + + + + + + + + + simple.documentation.framework.operations.highlight.EditHighlightsOperation + + + + + + false + + + + + remove_highlights + + + Remove Highlights + + + Remove highlights from the caret position + + + + + + + + + + + + + + + + + + + + + + + + simple.documentation.framework.operations.highlight.RemoveAllHighlightsOperation + + + + + + false + + + + + change_review_author + + + Change Review Author + + + Change the Review Author by selecting from a list of possible author names + + + + + + + + + + + + + + + + + + + + + + + + simple.documentation.framework.operations.highlight.ChangeReviewAuthorOperation + + + + + + false + + + + + open_new_editor + + + Open in new editor + + + Open a new XML editor containing the selected content + + + + + + + + + + + + + + + + + + true() + + + + + + simple.documentation.framework.operations.OpenInNewEditor + + + + + + false + + + + + debugger + + + debugger + + + Open a JS debugger + + + + + + + + + + + + M1 M2 D + + + + + + + + + + + script + doOperation = startDebugger; + + + + + ro.sync.ecss.extensions.commons.operations.JSOperation + + + + + + false + + + + + + + + SD Framework + + + + + + + + + + + + clients_report + + + + + insert_image + + + + + insert_section + + + + + Table + + + + + + + + + + + + insert_table + + + + + + + + + + + + + + + + + + + Contextual menu + + + + + + + + + + + + add_highlight + + + + + edit_highlights + + + + + remove_highlights + + + + + + transform + + + + + select_children + + + + + transform + + + + + show_file_status + + + + + refresh + + + + + clients_report + + + + + strict_mode + + + + + insert_image + + + + + insert_element + + + + + extract_node + + + + + open_new_editor + + + + + Table + + + + + + + + + + + + insert_table + + + + + + + + + + + insert_section + + + + + + + + + + + + + Toolbar + + + 2 + + + + + + + + + + + + change_review_author + + + + + + add_highlight + + + + + edit_highlights + + + + + remove_highlights + + + + + + transform + + + + + refresh + + + + + show_file_status + + + + + strict_mode + + + + + clients_report + + + + + inser_ref + + + + + insert_image + + + + + insert_table + + + + + insert_section + + + + + insert_element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${frameworkDir}/templates + + + + + ${framework}/catalog.xml + + + + A Simple Documentation Framework . + + + + + + http://www.oxygenxml.com/sample/documentation + + + * + + + * + + + * + + + simple.documentation.framework.CustomRule + + + * + + + * + + + * + + + + + * + + + * + + + *.sdf + + + * + + + + + + * + + + * + + + * + + + + + + + + + + + + SDF to HTML + + + + + + + + + pdf + + + Apache FOP + + + + + + ${framework}/xsl/sdf.xsl + + + ${currentFileURL} + + + false + + + false + + + XSL + + + true + + + false + + + + + + false + + + + + + false + + + true + + + true + + + false + + + false + + + true + + + + + + + + + Saxon-PE + + + + + + + + + + + + + + + + + + simple.documentation.framework.SDFExtensionsBundle + + + false + + + Text + + + + + + + + + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/oxygen/js-debugger-importer/sdf.jar b/oxygen/js-debugger-importer/sdf.jar new file mode 100644 index 0000000000000000000000000000000000000000..d7eac35c7b18a48ebf1beab3b1daa7ca6d03acf2 GIT binary patch literal 110627 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

    Cs6WvKCcdZTm4nf{O@H1VM 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 + + My Technical Book + + Jean + France + +

    + XML + Extensible Markup Language + In this section of the book I will explain different XML applications. +
    +
    + Accessing XML data. +
    + XSLT + Extensible stylesheet language transformation (XSLT) is a language for + transforming XML documents into other XML documents. + A list of XSL elements and what they do.. + +
    +
    + + + + + + + + + + + + + + + + + +
    XSLT ElementsDescription
    + 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
    +
    +
    + XPath + XPath (XML Path Language) is a terse (non-XML) syntax for addressing portions + of an XML document. + Some of the XPath functions. + +
    +
    + + + + + + + + + + + + + + +
    FunctionDescription
    format-numberThe 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
    currentThe current function returns a node-set that has the current node as + its only member.
    generate-idThe generate-id function returns a string that uniquely identifies + the node in the argument node-set that is first in document order.
    +
    +
    +
    + Documentation frameworks + One of the most important documentation frameworks is Docbook. + + The other is the topic oriented DITA, promoted by OASIS. + +
    + diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/AuthorAccessProvider.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/AuthorAccessProvider.java new file mode 100644 index 0000000..0b2d152 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/AuthorAccessProvider.java @@ -0,0 +1,16 @@ +package simple.documentation.framework; + +import ro.sync.ecss.extensions.api.AuthorAccess; + +/** + * Provides access to Author functions, to specific components corresponding to + * editor, document, workspace, tables, change tracking and utility informations and actions. + */ +public interface AuthorAccessProvider { + /** + * Gets access to Author functions and components. + * + * @return The Author access. + */ + AuthorAccess getAuthorAccess(); +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/CustomRule.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/CustomRule.java new file mode 100644 index 0000000..1fc57d6 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/CustomRule.java @@ -0,0 +1,44 @@ +package simple.documentation.framework; + +import org.xml.sax.Attributes; + +import ro.sync.ecss.extensions.api.DocumentTypeCustomRuleMatcher; + +/** + * Matching rule to the SDF document type. + * + */ +public class CustomRule implements DocumentTypeCustomRuleMatcher { + + /** + * Check if the SDF document type should be used for the given document properties. + */ + public boolean matches( + String systemID, + String rootNamespace, + String rootLocalName, + String doctypePublicID, + Attributes rootAttributes) { + boolean matches = true; + int attributesCount = rootAttributes.getLength(); + for (int i = 0; i < attributesCount; i++) { + String localName = rootAttributes.getLocalName(i); + if ("version".equals(localName)) { + if ("2.0".equals(rootAttributes.getValue(i))) { + // Do not match the documents with "2.0" version + matches = false; + } + } + } + + return matches; + } + + /** + * Description. + */ + public String getDescription() { + return "Checks if the current Document Type Association" + + " is matching the document."; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFElement.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFElement.java new file mode 100644 index 0000000..a26f0e3 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFElement.java @@ -0,0 +1,552 @@ +package simple.documentation.framework; + +import java.util.ArrayList; +import java.util.List; + +import ro.sync.contentcompletion.xml.CIAttribute; +import ro.sync.contentcompletion.xml.CIElement; +import ro.sync.contentcompletion.xml.CIElementAdapter; + +/** + * Simple Documentation Framework element. + */ +public class SDFElement extends CIElementAdapter { + /** + * The namespace. + */ + protected String namespace = null; + + /** + * The element name. + */ + protected String name = null; + + /** + * The proxy. + */ + protected String proxy = null; + + /** + * The type description. + */ + private String typeDescription = null; + + /** + * List of attributes. + */ + protected List attributes = null; + + /** + * The possible values as String list. + */ + private List possiblesValuesList; + + /** + * The element model description. + */ + private String modelDescription; + + /** + * The facets. One facet can be null if it is not defined. + */ + private String lengthFacetValue; + + /** + * The content type of the element. + */ + private int contentType = CONTENT_TYPE_NOT_DETERMINED; + + /** + * True if content is nillable. Used only for XML Schema. + */ + private boolean nillable; + + /** + * Facet values. + */ + private String minLengthFacetValue; + private String maxLengthFacetValue; + private String whitespaceFacetValue; + private String minInclusiveFacetValue; + private String minExclusiveFacetValue; + private String maxInclusiveFacetValue; + private String maxExclusiveFacetValue; + private String totalDigitsFacetValue; + private String fractionDigitsFacetValue; + private String facetPatternValue; + + /** + * Guess some following elements if possible + */ + protected List guessElements = null; + + /** + * @see ro.sync.contentcompletion.xml.CIElement#getGuessElements() + */ + @Override + public List getGuessElements() { + if (guessElements != null && guessElements.isEmpty()) { + // Return null is the list is empty. + return null; + } + return guessElements; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#addGuessElement(ro.sync.contentcompletion.xml.CIElement) + */ + @Override + public void addGuessElement(CIElement e) { + if (guessElements == null) { + guessElements = new ArrayList(); + } + guessElements.add(e); + } + + /** + * @return The string representing the name or null. + */ + @Override + public String getName(){ + return name; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#getNamespace() + */ + @Override + public String getNamespace(){ + return namespace; + } + + /** + * True if the element has a namespace. + */ + private boolean xmlns; + + /** + * @see ro.sync.contentcompletion.xml.CIElement#setDeclareXmlns(boolean) + */ + @Override + public void setDeclareXmlns(boolean xmlns) { + this.xmlns = xmlns; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#setContentType(int) + */ + @Override + public void setContentType(int contentType) { + this.contentType = contentType; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#isEmpty() + */ + @Override + public boolean isEmpty() { + return getContentType() == CONTENT_TYPE_EMPTY; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#getContentType() + */ + @Override + public int getContentType() { + return contentType; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#isDeclareXmlns() + */ + @Override + public boolean isDeclareXmlns() { + return xmlns; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#setName(java.lang.String) + */ + @Override + public void setName(String name) { + this.name = name; + } + /** + * @see ro.sync.contentcompletion.xml.CIElement#setPrefix(java.lang.String) + */ + @Override + public void setPrefix(String proxy) { + this.proxy = proxy; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#setNamespace(java.lang.String) + */ + @Override + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + + /** + * @see ro.sync.contentcompletion.xml.CIElement#getQName() + */ + @Override + public String getQName() { + if (getPrefix() != null && !"".equals(getPrefix())) { + return getPrefix() + ":" + getName(); + } else { + return getName(); + } + } + + /*** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + boolean result = false; + if (o instanceof SDFElement) { + CIElement cie = (CIElement) o; + result = compareTo(cie) == 0; + } + return result; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#getAttributes() + */ + @Override + public List getAttributes() { + return attributes; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#setAttributes(java.util.List) + */ + @Override + public void setAttributes(List attributes) { + this.attributes = attributes; + } + + /** + * Concatenates the name and the namespace and compares it with the other name and namespace, + * as strings. + * @param other The object to compare to. + * @return The value 0 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(List possiblesValuesList) { + this.possiblesValuesList = possiblesValuesList; + } + /** + * @param totalDigitsFacetValue The totalDigitsFacetValue to set. + */ + @Override + public void setFacetTotalDigitsValue(String totalDigitsFacetValue) { + this.totalDigitsFacetValue = totalDigitsFacetValue; + } + /** + * @param whitespaceFacetValue The whitespaceFacetValue to set. + */ + @Override + public void setFacetWhitespaceValue(String whitespaceFacetValue) { + this.whitespaceFacetValue = whitespaceFacetValue; + } + + /** + * @param lengthFacetValue The lengthFacetValue to set. + */ + @Override + public void setFacetLengthValue(String lengthFacetValue) { + this.lengthFacetValue = lengthFacetValue; + } + /** + * @param minLengthFacetValue The minLengthFacetValue to set. + */ + @Override + public void setFacetMinLengthValue(String minLengthFacetValue) { + this.minLengthFacetValue = minLengthFacetValue; + } + /** + * @param minExclusiveFacetValue The minExclusiveFacetValue to set. + */ + @Override + public void setFacetMinExclusiveValue(String minExclusiveFacetValue) { + this.minExclusiveFacetValue = minExclusiveFacetValue; + } + + /** + * @see ro.sync.contentcompletion.xml.NodeDescription#getFacetFractionDigitsValue() + */ + @Override + public String getFacetFractionDigitsValue() { + return fractionDigitsFacetValue; + } + + + /** + * @see ro.sync.contentcompletion.xml.NodeDescription#getFacetTotalDigitsValue() + */ + @Override + public String getFacetTotalDigitsValue() { + return totalDigitsFacetValue; + } + + + /** + * @see ro.sync.contentcompletion.xml.NodeDescription#getFacetMaxInclusiveValue() + */ + @Override + public String getFacetMaxInclusiveValue() { + return maxInclusiveFacetValue; + } + + /** + * @see ro.sync.contentcompletion.xml.NodeDescription#getFacetMaxExclusiveValue() + */ + @Override + public String getFacetMaxExclusiveValue() { + return maxExclusiveFacetValue; + } + + + /** + * Get the value of MIN_INCLUSIVE facet, can be null if it is not defined. + * + * @return The value of MIN_INCLUSIVE facet. + */ + @Override + public String getFacetMinInclusiveValue() { + return minInclusiveFacetValue; + } + + /** + * Get the value of MIN_EXCLUSIVE facet, can be null if it is not defined. + * + * @return The value of MIN_EXCLUSIVE facet. + */ + @Override + public String getFacetMinExclusiveValue() { + return minExclusiveFacetValue; + } + + /** + * Get the possible values as String list. + * + * @return The possible values. + */ + @Override + public List getPossibleValues() { + return possiblesValuesList; + } + + /** + * Get the model description. + * @return The model description. + */ + @Override + public String getModelDescription() { + return modelDescription; + } + /** + * Get the value of LENGTH facet, can be null if it is not defined. + * + * @return The value of length facet. + */ + @Override + public String getFacetLengthValue() { + return lengthFacetValue; + } + /** + * Get the value of MIN LENGTH facet, can be null if it is not defined. + * + * @return The value of MIN LENGTH facet. + */ + @Override + public String getFacetMinLengthValue() { + return minLengthFacetValue; + } + /** + * Get the value of MAX LENGTH facet, can be null if it is not defined. + * + * @return The value of MAX LENGTH facet. + */ + @Override + public String getFacetMaxLengthValue() { + return maxLengthFacetValue; + } + + /** + * Get the value of WHITESPACE facet, can be null if it is not defined. + * + * @return The value of WHITESPACE facet. + */ + @Override + public String getFacetWhitespaceValue() { + return whitespaceFacetValue; + } + + /** + * Get the list with pattern facets. + * + * @return The list with pattern facets, can be null if no FACET_PATTERN defined. + */ + @Override + public String getFacetPattern(){ + return facetPatternValue; + } + + /** + * Set the list with pattern facets. + * + * @param patternFacets The list with pattern facets. + */ + @Override + public void setFacetPattern(String patternFacets){ + this.facetPatternValue = patternFacets; + } + + /** + * The annotation string, null as default. + */ + protected String annotation; + + /** + * Get the annotation for the element. + * + * @return A text that explain how to use the attribute, or null. + */ + @Override + public String getAnnotation() { + return annotation; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#setAnnotation(java.lang.String) + */ + @Override + public void setAnnotation(String annotation){ + this.annotation = annotation; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#getTypeDescription() + */ + @Override + public String getTypeDescription() { + return typeDescription; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#setTypeDescription(java.lang.String) + */ + @Override + public void setTypeDescription(String typeDescription) { + this.typeDescription = typeDescription; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#setNillable(boolean) + */ + @Override + public void setNillable(boolean nillable) { + this.nillable = nillable; + } + + /** + * @see ro.sync.contentcompletion.xml.CIElement#isNillable() + */ + @Override + public boolean isNillable() { + return nillable; + } +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFExtensionsBundle.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFExtensionsBundle.java new file mode 100644 index 0000000..cf69612 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFExtensionsBundle.java @@ -0,0 +1,173 @@ +package simple.documentation.framework; + +import ro.sync.contentcompletion.xml.SchemaManagerFilter; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorExtensionStateListener; +import ro.sync.ecss.extensions.api.AuthorExternalObjectInsertionHandler; +import ro.sync.ecss.extensions.api.AuthorReferenceResolver; +import ro.sync.ecss.extensions.api.AuthorSchemaAwareEditingHandler; +import ro.sync.ecss.extensions.api.AuthorTableCellSpanProvider; +import ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider; +import ro.sync.ecss.extensions.api.CustomAttributeValueEditor; +import ro.sync.ecss.extensions.api.ExtensionsBundle; +import ro.sync.ecss.extensions.api.StylesFilter; +import ro.sync.ecss.extensions.api.link.ElementLocatorProvider; +import ro.sync.ecss.extensions.api.link.LinkTextResolver; +import ro.sync.ecss.extensions.api.structure.AuthorBreadCrumbCustomizer; +import ro.sync.ecss.extensions.api.structure.AuthorOutlineCustomizer; +import ro.sync.ecss.extensions.commons.DefaultElementLocatorProvider; +import simple.documentation.framework.extensions.SDFAttributesValueEditor; +import simple.documentation.framework.extensions.SDFAuthorBreadCrumbCustomizer; +import simple.documentation.framework.extensions.SDFAuthorExtensionStateListener; +import simple.documentation.framework.extensions.SDFAuthorOutlineCustomizer; +import simple.documentation.framework.extensions.SDFExternalObjectInsertionHandler; +import simple.documentation.framework.extensions.SDFReferencesResolver; +import simple.documentation.framework.extensions.SDFSchemaAwareEditingHandler; +import simple.documentation.framework.extensions.SDFSchemaManagerFilter; +import simple.documentation.framework.extensions.SDFStylesFilter; +import simple.documentation.framework.extensions.TableCellSpanProvider; +import simple.documentation.framework.extensions.TableColumnWidthProvider; + +/** + * Simple Document Framework extension bundle. + * + */ +public class SDFExtensionsBundle extends ExtensionsBundle { + /** + * Simple documentation framework state listener. + */ + private SDFAuthorExtensionStateListener sdfAuthorExtensionStateListener; + + /** + * Editor for attributes values. + */ + @Override + public CustomAttributeValueEditor createCustomAttributeValueEditor(boolean forEclipsePlugin) { + return new SDFAttributesValueEditor(new AuthorAccessProvider() { + + public AuthorAccess getAuthorAccess() { + AuthorAccess access = null; + if (sdfAuthorExtensionStateListener != null) { + // Get the Author access. + access = sdfAuthorExtensionStateListener.getAuthorAccess(); + } + return access; + } + }); + } + + /** + * Simple documentation framework state listener. + */ + @Override + public AuthorExtensionStateListener createAuthorExtensionStateListener() { + sdfAuthorExtensionStateListener = new SDFAuthorExtensionStateListener(); + return sdfAuthorExtensionStateListener; + } + + /** + * Filter for content completion proposals from the schema manager. + */ + @Override + public SchemaManagerFilter createSchemaManagerFilter() { + return new SDFSchemaManagerFilter(); + } + + /** + * Default element locator. + */ + @Override + public ElementLocatorProvider createElementLocatorProvider() { + return new DefaultElementLocatorProvider(); + } + + /** + * Expand content references. + */ + @Override + public AuthorReferenceResolver createAuthorReferenceResolver() { + return new SDFReferencesResolver(); + } + + /** + * CSS styles filtering. + */ + @Override + public StylesFilter createAuthorStylesFilter() { + return new SDFStylesFilter(); + } + + /** + * Provider for table cell span informations. + */ + @Override + public AuthorTableCellSpanProvider createAuthorTableCellSpanProvider() { + return new TableCellSpanProvider(); + } + + /** + * Table column width provider responsible of handling modifications regarding + * table width and column widths. + */ + @Override + public AuthorTableColumnWidthProvider createAuthorTableColumnWidthProvider() { + return new TableColumnWidthProvider(); + } + + /** + * Editing support for SDF documents responsible of handling typing and paste events inside section and tables. + */ + @Override + public AuthorSchemaAwareEditingHandler getAuthorSchemaAwareEditingHandler() { + return new SDFSchemaAwareEditingHandler(); + } + + /** + * Author Outline customizer used for custom filtering and nodes rendering in the Outline. + */ + @Override + public AuthorOutlineCustomizer createAuthorOutlineCustomizer() { + return new SDFAuthorOutlineCustomizer(); + } + + /** + * Simple Document Framework Author customizer used for custom nodes rendering + * in the Breadcrumb. + */ + @Override + public AuthorBreadCrumbCustomizer createAuthorBreadCrumbCustomizer() { + return new SDFAuthorBreadCrumbCustomizer(); + } + + /** + * @see ro.sync.ecss.extensions.api.ExtensionsBundle#createExternalObjectInsertionHandler() + */ + @Override + public AuthorExternalObjectInsertionHandler createExternalObjectInsertionHandler() { + return new SDFExternalObjectInsertionHandler(); + } + + /** + * The unique identifier of the Document Type. + * This identifier will be used to store custom SDF options. + */ + @Override + public String getDocumentTypeID() { + return "Simple.Document.Framework.document.type"; + } + + /** + * Bundle description. + */ + public String getDescription() { + return "A custom extensions bundle used for the Simple Document Framework"; + } + + /** + * @see ro.sync.ecss.extensions.api.ExtensionsBundle#createLinkTextResolver() + */ + @Override + public LinkTextResolver createLinkTextResolver() { + return new SDFLinkTextResolver(); + } +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFLinkTextResolver.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFLinkTextResolver.java new file mode 100644 index 0000000..8fd2adc --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/SDFLinkTextResolver.java @@ -0,0 +1,72 @@ +package simple.documentation.framework; + +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.link.InvalidLinkException; +import ro.sync.ecss.extensions.api.link.LinkTextResolver; +import ro.sync.ecss.extensions.api.node.AttrValue; +import ro.sync.ecss.extensions.api.node.AuthorElement; +import ro.sync.ecss.extensions.api.node.AuthorNode; + +/** + * Resolve a link and obtains a text representation. The content of the link represent the name and + * the absolute location of the referred file. + */ +public class SDFLinkTextResolver extends LinkTextResolver { + + /** + * The author access. + */ + private AuthorAccess authorAccess; + + /** + * Logger for logging. + */ + private static final Logger logger = LogManager.getLogger(SDFLinkTextResolver.class.getName()); + + + /** + * @see ro.sync.ecss.extensions.api.link.LinkTextResolver#resolveReference(ro.sync.ecss.extensions.api.node.AuthorNode) + */ + @Override + public String resolveReference(AuthorNode node) throws InvalidLinkException { + String linkText = null; + if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT + && "link".equals(ro.sync.basic.xml.BasicXmlUtil.getLocalName(node.getName()))) { + AuthorElement element = (AuthorElement) node; + AuthorElement[] authorElements = element.getElementsByLocalName("ref"); + + if (authorElements != null && authorElements.length > 0) { + // Get the first 'ref' element from link. + AuthorElement refElem = authorElements[0]; + AttrValue locationAttribute = refElem.getAttribute("location"); + String locationVal = locationAttribute.getValue(); + URIResolver uriResolver = authorAccess.getXMLUtilAccess().getURIResolver(); + try { + Source resolve = uriResolver.resolve(locationVal, authorAccess.getEditorAccess().getEditorLocation().toString()); + String systemId = resolve.getSystemId(); + linkText = "[" + locationVal + "] - " + systemId; + } catch (TransformerException e) { + logger.warn(e, e); + } + } + } + + return linkText; + } + + + /** + * @see ro.sync.ecss.extensions.api.link.LinkTextResolver#activated(ro.sync.ecss.extensions.api.AuthorAccess) + */ + @Override + public void activated(AuthorAccess authorAccess) { + this.authorAccess = authorAccess; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/callouts/CalloutsRenderingProvider.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/callouts/CalloutsRenderingProvider.java new file mode 100644 index 0000000..ff1e884 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/callouts/CalloutsRenderingProvider.java @@ -0,0 +1,95 @@ +package simple.documentation.framework.callouts; + +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.swing.text.BadLocationException; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorDocumentController; +import ro.sync.ecss.extensions.api.callouts.AuthorCalloutRenderingInformation; +import ro.sync.ecss.extensions.api.callouts.CalloutsRenderingInformationProvider; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight; +import ro.sync.ecss.extensions.api.node.AuthorNode; +import ro.sync.exml.view.graphics.Color; + + +/** + * Callouts rendering provider. + * + * @author marius + */ +public class CalloutsRenderingProvider extends CalloutsRenderingInformationProvider { + /** + * The author access. + */ + private final AuthorAccess authorAccess; + + /** + * Constructor. + * + * @param authorAccess The author access. + */ + public CalloutsRenderingProvider(AuthorAccess authorAccess) { + this.authorAccess = authorAccess; + } + + @Override + public boolean shouldRenderAsCallout(AuthorPersistentHighlight persistentHighlight) { + return true; + } + + @Override + public AuthorCalloutRenderingInformation getCalloutRenderingInformation( + final AuthorPersistentHighlight hl) { + return new AuthorCalloutRenderingInformation() { + + @Override + public long getTimestamp() { + return -1; + } + + @Override + public String getContentFromTarget(int arg0) { + try { + AuthorDocumentController documentController = authorAccess.getDocumentController(); + AuthorNode nodeAtOffset = documentController.getNodeAtOffset(hl.getEndOffset()); + int startOffset = hl.getStartOffset() - nodeAtOffset.getStartOffset(); + int endOffset = hl.getEndOffset() - nodeAtOffset.getEndOffset(); + String textContent = nodeAtOffset.getTextContent(); + return textContent.substring(startOffset, endOffset); + } catch (BadLocationException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public String getComment(int arg0) { + return hl.getClonedProperties().get(AuthorPersistentHighlight.COMMENT_ATTRIBUTE); + } + + @Override + public Color getColor() { + return Color.COLOR_DARK_YELLOW; + } + + @Override + public String getCalloutType() { + return "Paragraph review"; + } + + @Override + public String getAuthor() { + return "para_reviewer"; + } + + @Override + public Map getAdditionalData() { + LinkedHashMap clonedProperties = hl.getClonedProperties(); + clonedProperties.put("Level", "Superior"); + return clonedProperties; + } + }; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/callouts/SDFAuthorPersistentHighlightActionsProvider.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/callouts/SDFAuthorPersistentHighlightActionsProvider.java new file mode 100644 index 0000000..87a9d5d --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/callouts/SDFAuthorPersistentHighlightActionsProvider.java @@ -0,0 +1,63 @@ +package simple.documentation.framework.callouts; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.swing.AbstractAction; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlightActionsProvider; +import ro.sync.exml.workspace.api.editor.page.author.actions.AuthorActionsProvider; + +/** + * Provides actions that are shown on the contextual menu of the callout + */ +public class SDFAuthorPersistentHighlightActionsProvider implements + AuthorPersistentHighlightActionsProvider { + /** + * The list with contextual actions for a custom callout. + */ + private List actions = new ArrayList(); + /** + * The default action. + */ + private AbstractAction defaultAction; + /** + * Constructor. + * + * @param authorAccess The author access. + */ + public SDFAuthorPersistentHighlightActionsProvider(AuthorAccess authorAccess) { + AuthorActionsProvider actionsProvider = authorAccess.getEditorAccess().getActionsProvider(); + Map authorCommonActions = actionsProvider.getAuthorCommonActions(); + Set keySet = authorCommonActions.keySet(); + for (String key : keySet) { + if (key != null) { + if ("Edit/Add_Comment".equals(key) || + "Edit/Edit_Comment".equals(key) || + "Edit/Remove_Comments".equals(key)) { + actions.add((AbstractAction) authorCommonActions.get(key)); + if ("Edit/Edit_Comment".equals(key)) { + defaultAction = (AbstractAction) authorCommonActions.get(key); + } + } + } + } + } + /** + * @see ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlightActionsProvider#getDefaultAction(ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight) + */ + public AbstractAction getDefaultAction(AuthorPersistentHighlight hl) { + return defaultAction; + } + + /** + * @see ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlightActionsProvider#getActions(ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight) + */ + public List getActions(AuthorPersistentHighlight hl) { + return actions; + } +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAttributesValueEditor.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAttributesValueEditor.java new file mode 100644 index 0000000..bb60a70 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAttributesValueEditor.java @@ -0,0 +1,69 @@ +package simple.documentation.framework.extensions; + +import java.io.File; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.CustomAttributeValueEditor; +import ro.sync.ecss.extensions.api.EditedAttribute; +import simple.documentation.framework.AuthorAccessProvider; + +/** + * Simple Document Framework attributes value editor. + */ +public class SDFAttributesValueEditor extends CustomAttributeValueEditor { + /** + * Provides access to Author functions and components. + */ + private final AuthorAccessProvider authorAccessProvider; + + /** + * Constructor. + * + * @param authorAccessProvider Provides access to Author functions and components. + */ + public SDFAttributesValueEditor(AuthorAccessProvider authorAccessProvider) { + this.authorAccessProvider = authorAccessProvider; + } + + /** + * Get the value for the current attribute. + * + * @param attr The Edited attribute information. + * @param parentComponent The parent component/composite. + */ + public String getAttributeValue(EditedAttribute attr, Object parentComponent) { + String refValue = null; + AuthorAccess authorAccess = authorAccessProvider.getAuthorAccess(); + if (authorAccess != null) { + File refFile = authorAccess.getWorkspaceAccess().chooseFile( + // Title + "Choose reference file", + // Extensions + null, + // Filter description + null, + // Open for save + false); + if (refFile != null) { + refValue = refFile.getAbsolutePath(); + } + } + return refValue; + } + + /** + * Description of the attribute value editor. + */ + @Override + public String getDescription() { + return "Reference attribute value editor"; + } + + /** + * Filters the attributes that it handles. + */ + @Override + public boolean shouldHandleAttribute(EditedAttribute attribute) { + return attribute.getAttributeQName().endsWith("ref"); + } +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorBreadCrumbCustomizer.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorBreadCrumbCustomizer.java new file mode 100644 index 0000000..b376aee --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorBreadCrumbCustomizer.java @@ -0,0 +1,60 @@ +package simple.documentation.framework.extensions; + +import javax.swing.JPopupMenu; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.node.AuthorNode; +import ro.sync.ecss.extensions.api.structure.AuthorBreadCrumbCustomizer; +import ro.sync.ecss.extensions.api.structure.RenderingInformation; + +/** + * Simple Document Framework Author customizer used for custom nodes rendering + * in the Breadcrumb. + */ +public class SDFAuthorBreadCrumbCustomizer extends AuthorBreadCrumbCustomizer { + + /** + * For every node render its name in the Outline (with the first letter capitalized). + * Set 'Paragraph' as render for 'para' nodes + */ + @Override + public void customizeRenderingInformation(RenderingInformation renderInfo) { + // Get the node to be rendered + AuthorNode node = renderInfo.getNode(); + + String name = node.getName(); + if (name.length() > 0) { + if ("para".equals(name)) { + name = "Paragraph"; + } else { + if(renderInfo.getNode().getName().equals("customcol")) { + // Do not display the customcol elements in the BreadCrumb + name = null; + } else { + // Capitalize the first letter + name = name.substring(0, 1).toUpperCase() + name.substring(1, name.length()); + } + } + } + + if (name == null) { + renderInfo.setIgnoreNodeFromDisplay(true); + } else { + // Set the render text + renderInfo.setRenderedText("[" + name + "]"); + } + } + + /** + * Don't show the popUp menu for the bread crumb. + */ + @Override + public void customizePopUpMenu(Object popUp, AuthorAccess authorAccess) { + if (popUp instanceof JPopupMenu) { + JPopupMenu popupMenu = (JPopupMenu)popUp; + // Remove all the components from the popUp menu . + popupMenu.removeAll(); + } + } + +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorExtensionStateListener.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorExtensionStateListener.java new file mode 100644 index 0000000..95115bd --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorExtensionStateListener.java @@ -0,0 +1,374 @@ +package simple.documentation.framework.extensions; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorCaretListener; +import ro.sync.ecss.extensions.api.AuthorExtensionStateListener; +import ro.sync.ecss.extensions.api.AuthorListener; +import ro.sync.ecss.extensions.api.AuthorMouseListener; +import ro.sync.ecss.extensions.api.OptionChangedEvent; +import ro.sync.ecss.extensions.api.OptionListener; +import ro.sync.ecss.extensions.api.callouts.AuthorCalloutsController; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight.PersistentHighlightType; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlighter; +import ro.sync.ecss.extensions.api.highlights.ColorHighlightPainter; +import ro.sync.ecss.extensions.api.highlights.HighlightPainter; +import ro.sync.ecss.extensions.api.highlights.PersistentHighlightRenderer; +import ro.sync.ecss.extensions.api.structure.AuthorPopupMenuCustomizer; +import ro.sync.exml.view.graphics.Color; +import ro.sync.exml.workspace.api.Platform; +import ro.sync.exml.workspace.api.editor.page.author.actions.AuthorActionsProvider; +import ro.sync.basic.util.URLUtil; +import simple.documentation.framework.callouts.CalloutsRenderingProvider; +import simple.documentation.framework.callouts.SDFAuthorPersistentHighlightActionsProvider; +import simple.documentation.framework.filters.SDFDocumentFilter; +import simple.documentation.framework.listeners.SDFAuthorCaretListener; +import simple.documentation.framework.listeners.SDFAuthorListener; +import simple.documentation.framework.listeners.SDFAuthorMouseListener; +import simple.documentation.framework.operations.highlight.HighlightProperties; + +/** + * Simple Document Framework state listener used to register custom listeners(caret listener, mouse + * listener, document listener and option listener) when the framework is activated. + * + */ +public class SDFAuthorExtensionStateListener implements AuthorExtensionStateListener { + /** + * The key used to store a custom option. + */ + private String customKey = "sdf.custom.option.key"; + + /** + * Custom caret listener to be added on activate and removed on deactivate + */ + private AuthorCaretListener sdfCaretListener; + + /** + * Custom mouse listener + */ + private AuthorMouseListener sdfMouseListener; + + /** + * Option listener to be added in the option storage. + */ + private OptionListener sdfOptionListener; + + /** + * Custom author listener + */ + private AuthorListener sdfAuthorDocumentListener; + + /** + * The access to the author functions. + */ + private AuthorAccess authorAccess; + + /** + * Map between author name and the corresponding highlight/colors association + */ + public static Map> authorHighlightColors = null; + + /** + * Defines the color for a highlight + */ + public static class HighlightColors { + private Color bgColor; + private Color decorationColor; + + /** + * @param bgColor The background color. + * @param decorationColor The color used for decoration + */ + public HighlightColors(Color bgColor, Color decorationColor) { + super(); + this.bgColor = bgColor; + this.decorationColor = decorationColor; + } + + /** + * @return Returns the bgColor. + */ + public Color getBgColor() { + return bgColor; + } + + /** + * @return Returns the decorationColor. + */ + public Color getDecorationColor() { + return decorationColor; + } + } + + static { + authorHighlightColors = new HashMap>(); + + // Set colors for Author_1 + Map colorsMap = new HashMap(); + // Set colors for Insert Change highlight + colorsMap.put(PersistentHighlightType.CHANGE_INSERT, + new HighlightColors(new Color(230, 255, 230), new Color(130, 255, 130))); + // Set colors for Delete Change highlight + colorsMap.put(PersistentHighlightType.CHANGE_DELETE, + new HighlightColors(new Color(255, 255, 230), new Color(255, 255, 130))); + authorHighlightColors.put("Author_1", colorsMap); + + // Set colors for Author_2 + colorsMap = new HashMap(); + // Set colors for Insert Change highlight + colorsMap.put(PersistentHighlightType.CHANGE_INSERT, + new HighlightColors(new Color(255, 255, 230), new Color(255, 255, 130))); + // Set colors for Delete Change highlight + colorsMap.put(PersistentHighlightType.CHANGE_DELETE, + new HighlightColors(new Color(240, 240, 240), new Color(64, 64, 64))); + authorHighlightColors.put("Author_2", colorsMap); + } + + /** + * The SDF Author extension is activated. + */ + public void activated(final AuthorAccess authorAccess) { + this.authorAccess = authorAccess; + sdfOptionListener = new OptionListener(customKey) { + @Override + public void optionValueChanged(OptionChangedEvent newValue) { + // The custom option changed. + } + }; + + // Add document filter. + authorAccess.getDocumentController().setDocumentFilter(new SDFDocumentFilter(authorAccess)); + + // Add an option listener. + authorAccess.getOptionsStorage().addOptionListener(sdfOptionListener); + + // Add author document listeners. + sdfAuthorDocumentListener = new SDFAuthorListener(authorAccess); + authorAccess.getDocumentController().addAuthorListener(sdfAuthorDocumentListener); + + if (authorAccess.getWorkspaceAccess().getPlatform() != Platform.WEBAPP) { + // Add mouse listener. + sdfMouseListener = new SDFAuthorMouseListener(authorAccess); + authorAccess.getEditorAccess().addAuthorMouseListener(sdfMouseListener); + + // Add custom tooltip + String tooltip = "[SDF] " + URLUtil.getDescription(authorAccess.getEditorAccess().getEditorLocation()); + authorAccess.getEditorAccess().setEditorTabTooltipText(tooltip); + + // Add caret listener. + sdfCaretListener = new SDFAuthorCaretListener(authorAccess); + //authorAccess.getEditorAccess().addAuthorCaretListener(sdfCaretListener); + + // Use the actions provider to switch to "No Tags" mode. + AuthorActionsProvider actionsProvider = authorAccess.getEditorAccess().getActionsProvider(); + Map authorCommonActions = actionsProvider.getAuthorCommonActions(); + // Switch to no tags Author/No_tags + actionsProvider.invokeAction(authorCommonActions.get("Author/No_tags")); + + // Set highlights tool tip and painter + authorAccess.getEditorAccess().getPersistentHighlighter().setHighlightRenderer(new PersistentHighlightRenderer() { + public String getTooltip(AuthorPersistentHighlight highlight) { + // Get highlight properties + Map properties = highlight.getClonedProperties(); + String highlightID = properties.get(HighlightProperties.ID); + String highlightAuthor = properties.get(HighlightProperties.AUTHOR); + String highlightComment = properties.get(HighlightProperties.COMMENT); + + StringBuilder tooltip = new StringBuilder(); + // Add create date + if (highlightID != null) { + try { + tooltip.append("Id: ").append(highlightID).append("\n"); + } catch (NumberFormatException e) { + // Wrong date + } + } + // Add author + if (highlightAuthor != null) { + tooltip.append("Author: ").append(highlightAuthor).append("\n");; + } + // Add comment + if (highlightComment != null) { + tooltip.append("Comment: ").append(highlightComment); + } + return tooltip.toString(); + } + + public HighlightPainter getHighlightPainter(AuthorPersistentHighlight highlight) { + ColorHighlightPainter painter = new ColorHighlightPainter(); + painter.setBgColor(new Color(0, 0, 255, 20)); + return painter; + } + }); + + // Set reviews tool tip and painters + authorAccess.getReviewController().setReviewRenderer(new PersistentHighlightRenderer() { + /** + * @see ro.sync.ecss.extensions.api.highlights.PersistentHighlightRenderer#getTooltip(ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight) + */ + public String getTooltip(AuthorPersistentHighlight highlight) { + String tooltip = "Review Tooltip"; + + PersistentHighlightType type = highlight.getType(); + if (type == PersistentHighlightType.CHANGE_DELETE) { + // Delete highlight + tooltip = "Deleted by " + highlight.getClonedProperties().get("author"); + } else if (type == PersistentHighlightType.CHANGE_INSERT) { + // Insert highlight + tooltip = "Inserted by " + highlight.getClonedProperties().get("author"); + } else if (type == PersistentHighlightType.COMMENT) { + // Comment highlight + // If a null value is returned, the default tooltip text will be used + tooltip = null; + } + return tooltip; + } + + /** + * @see ro.sync.ecss.extensions.api.highlights.PersistentHighlightRenderer#getHighlightPainter(ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight) + */ + public HighlightPainter getHighlightPainter(AuthorPersistentHighlight highlight) { + HighlightPainter reviewPainter = null; + Map properties = highlight.getClonedProperties(); + String authorName = properties.get("author"); + if (authorName != null) { + // Get the highlight/colors association for this author name + Map highlightColorsMap = authorHighlightColors.get(authorName); + if (highlightColorsMap != null) { + // Get the associated colors for this type of highlight + HighlightColors highlightColors = highlightColorsMap.get(highlight.getType()); + if (highlightColors != null) { + reviewPainter = new ColorHighlightPainter(); + // Background color + ((ColorHighlightPainter) reviewPainter).setBgColor(highlightColors.getBgColor()); + // Decoration color + ((ColorHighlightPainter) reviewPainter).setColor(highlightColors.getDecorationColor()); + } + } + } + + // If a null value is returned the default highlight painter is used. + return reviewPainter; + } + }); + + // Get the list with all track changes highlights from the document + AuthorPersistentHighlight[] changeHighlights = authorAccess.getReviewController().getChangeHighlights(); + if(changeHighlights.length > 0 && !authorAccess.getReviewController().isTrackingChanges()) { + // If the document has track changes highlights, then set track changes mode to ON + authorAccess.getReviewController().toggleTrackChanges(); + } + + // Add a popup menu customizer. Group Cut, Copy, Paste and Paste as XML actions in Edit menu. + authorAccess.getEditorAccess().addPopUpMenuCustomizer(new AuthorPopupMenuCustomizer() { + // Customize popup menu + @SuppressWarnings("serial") + public void customizePopUpMenu(Object popUp, final AuthorAccess authorAccess) { + JPopupMenu popupMenu = (JPopupMenu) popUp; + Component[] components = popupMenu.getComponents(); + // The new 'Edit' menu + JMenu editMenu = new JMenu("Edit"); + boolean shouldAddEditMenu = false; + for (int i = 0; i < components.length; i++) { + if (components[i] instanceof JMenuItem) { + JMenuItem menuItem = (JMenuItem) components[i]; + if (menuItem.getAction() != null) { + Object name = menuItem.getAction().getValue(Action.NAME); + if ("Cut".equals(name) || "Copy".equals(name) || "Paste".equals(name)|| "Paste as XML".equals(name)) { + // Remove edit actions + popupMenu.remove(menuItem); + // Add edit actions to edit menu + editMenu.add(menuItem); + shouldAddEditMenu = true; + } + } + } + } + if (shouldAddEditMenu) { + popupMenu.add(editMenu, 0); + } + + final URL selectedUrl; + try { + final String selectedText = authorAccess.getEditorAccess().getSelectedText(); + if (selectedText != null) { + selectedUrl = new URL(selectedText); + // Open selected url in system application + popupMenu.add(new JMenuItem(new AbstractAction("Open in system application") { + public void actionPerformed(ActionEvent e) { + authorAccess.getWorkspaceAccess().openInExternalApplication(selectedUrl, true); + } + }), 0); + } + } catch (MalformedURLException e2) {} + } + }); + + // Add a provider for callouts rendering + CalloutsRenderingProvider calloutsRenderingProvider = new CalloutsRenderingProvider(authorAccess); + AuthorCalloutsController authorCalloutsController = + authorAccess.getReviewController().getAuthorCalloutsController(); + authorCalloutsController.setCalloutsRenderingInformationProvider(calloutsRenderingProvider); + + // Show insertions callouts + authorCalloutsController.setShowInsertionsCallouts(true); + + // Add an actions provider for actions that are shown on the contextual menu of the + // custom callout + AuthorPersistentHighlighter highlighter = authorAccess.getEditorAccess().getPersistentHighlighter(); + SDFAuthorPersistentHighlightActionsProvider highlightActionsProvider = + new SDFAuthorPersistentHighlightActionsProvider(authorAccess); + highlighter.setHighlightsActionsProvider(highlightActionsProvider); + } + + // Other custom initializations... + } + + /** + * The SDF Author extension is deactivated. + */ + public void deactivated(AuthorAccess authorAccess) { + + // Remove the option listener. + authorAccess.getOptionsStorage().removeOptionListener(sdfOptionListener); + + // Remove document listeners. + authorAccess.getDocumentController().removeAuthorListener(sdfAuthorDocumentListener); + + if (authorAccess.getWorkspaceAccess().getPlatform() != Platform.WEBAPP) { + // Remove mouse listener. + authorAccess.getEditorAccess().removeAuthorMouseListener(sdfMouseListener); + + // Remove caret listener. + authorAccess.getEditorAccess().removeAuthorCaretListener(sdfCaretListener); + } + + // Other actions... + } + + public String getDescription() { + return "Simple Document Framework state listener"; + } + + /** + * Returns the Author access. + * + * @return The access to Author functions and components. + */ + public AuthorAccess getAuthorAccess() { + return authorAccess; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorOutlineCustomizer.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorOutlineCustomizer.java new file mode 100644 index 0000000..172dc19 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFAuthorOutlineCustomizer.java @@ -0,0 +1,158 @@ +package simple.documentation.framework.extensions; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.text.BadLocationException; +import javax.swing.tree.TreePath; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.node.AuthorElement; +import ro.sync.ecss.extensions.api.node.AuthorNode; +import ro.sync.ecss.extensions.api.structure.AuthorOutlineCustomizer; +import ro.sync.ecss.extensions.api.structure.RenderingInformation; + +/** + * Simple Document Framework Author Outline customizer used for custom filtering and nodes rendering + * in the Outline. + */ +public class SDFAuthorOutlineCustomizer extends AuthorOutlineCustomizer { + + /** + * Ignore 'b' nodes. + */ + @Override + public boolean ignoreNode(AuthorNode node) { + if (node.getName().equals("b")) { + return true; + } + // Default behavior + return false; + } + + /** + * For every node render its name in the Outline (with the first letter capitalized). + * Set 'Paragraph' as render for 'para' nodes + * Render the title text for 'section' nodes and add 'Section' as additional info and tooltip. + */ + @Override + public void customizeRenderingInformation( + RenderingInformation renderInfo) { + // Get the node to be rendered + AuthorNode node = renderInfo.getNode(); + + String name = node.getName(); + if (name.length() > 0) { + if ("para".equals(name)) { + name = "Paragraph"; + } else { + // Capitalize the first letter + name = name.substring(0, 1).toUpperCase() + name.substring(1, name.length()); + } + } + + // Render additional attribute value + String additionalAttrValue = renderInfo.getAdditionalRenderedAttributeValue(); + if (additionalAttrValue != null && additionalAttrValue.length() > 0) { + renderInfo.setAdditionalRenderedAttributeValue("[" + additionalAttrValue + "]"); + } + + // Set the render text + renderInfo.setRenderedText("[" + name + "]"); + + // Render the title text in the 'section' additional info. + if (node.getName().equals("section")) { + if (node instanceof AuthorElement) { + // Get the 'section' content nodes + List contentNodes = ((AuthorElement) node).getContentNodes(); + if (contentNodes.size() > 0) { + AuthorNode authorNode = contentNodes.get(0); + if ("title".equals(authorNode.getName())) { + try { + // Render the title + String textContent = authorNode.getTextContent(); + if (textContent != null && textContent.trim().length() > 0) { + if (textContent.length() > 20) { + textContent = textContent.substring(0, 20); + } + renderInfo.setRenderedText(textContent); + // Set 'Section' as additional info + renderInfo.setAdditionalRenderedText("[Section]"); + // Set the tooltip text + renderInfo.setTooltipText(textContent); + } + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + } + } + } + } + + /** + * Customize the popUp menu. + * If the selected node is a 'title' from 'section' remove the 'Delete' + * action from the popUp menu and add the 'Remove content' action if the selection + * is single. + */ + @Override + public void customizePopUpMenu(Object popUp, final AuthorAccess authorAccess) { + if (authorAccess != null) { + if (popUp instanceof JPopupMenu) { + JPopupMenu popupMenu = (JPopupMenu)popUp; + // Find the selected paths from the Outliner + TreePath[] selectedPaths = authorAccess.getOutlineAccess().getSelectedPaths(true); + for (TreePath treePath : selectedPaths) { + Object[] authorNodesPath = treePath.getPath(); + if (authorNodesPath.length > 0) { + // Find the selected node (last node from the list of path nodes) + final AuthorNode selectedAuthorNode = (AuthorNode) authorNodesPath[authorNodesPath.length - 1]; + // Find if the current selected node is a title from section + if ("title".equals(selectedAuthorNode.getName()) && + "section".equals(selectedAuthorNode.getParent().getName())) { + // Find the popUp item corresponding to the 'Delete' action + Component[] components = popupMenu.getComponents(); + int deleteItemIndex = 0; + for (int i = 0; i < components.length; i++) { + if (components[i] instanceof JMenuItem) { + String itemText = ((JMenuItem) components[i]).getText(); + if ("Delete".equals(itemText)) { + // The 'Remove Content' item will be added at the same index + deleteItemIndex = i; + // Remove the 'Delete' action + popupMenu.remove(deleteItemIndex); + } + } + } + + if (selectedPaths.length == 1) { + // Add the 'Remove content' action + JMenuItem sdfMenuItem = new JMenuItem("Remove Content"); + sdfMenuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + // Remove title content + int startOffset = selectedAuthorNode.getStartOffset(); + int endOffset = selectedAuthorNode.getEndOffset(); + if (endOffset > startOffset + 1) { + authorAccess.getDocumentController().delete( + startOffset + 1, + endOffset); + } + } + }); + // Add the menu item in the menu + popupMenu.add(sdfMenuItem, deleteItemIndex); + } + break; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFExternalObjectInsertionHandler.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFExternalObjectInsertionHandler.java new file mode 100644 index 0000000..48cbb20 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFExternalObjectInsertionHandler.java @@ -0,0 +1,72 @@ +package simple.documentation.framework.extensions; + +import java.net.URL; +import java.util.List; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorExternalObjectInsertionHandler; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment; +import ro.sync.basic.util.URLUtil; + +/** + * Accepts insertion of images and XML files from external sources. + */ +public class SDFExternalObjectInsertionHandler extends AuthorExternalObjectInsertionHandler { + /** + * @see ro.sync.ecss.extensions.api.AuthorExternalObjectInsertionHandler#insertURLs(ro.sync.ecss.extensions.api.AuthorAccess, java.util.List, int) + */ + @Override + public void insertURLs(AuthorAccess authorAccess, List urls, int source) + throws AuthorOperationException { + for (URL url : urls) { + String xmlFragment = null; + if (authorAccess.getUtilAccess().isSupportedImageURL(url)) { + // Insert an image element + xmlFragment = ""; + } else { + // Insert + xmlFragment = ""; + } + if (xmlFragment != null) { + // Create am image fragment + AuthorDocumentFragment imageFragment = authorAccess.getDocumentController().createNewDocumentFragmentInContext( + xmlFragment, authorAccess.getEditorAccess().getCaretOffset()); + // Insert the fragment + authorAccess.getDocumentController().insertFragment(authorAccess.getEditorAccess().getCaretOffset(), imageFragment); + } + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorExternalObjectInsertionHandler#acceptSource(ro.sync.ecss.extensions.api.AuthorAccess, int) + */ + @Override + public boolean acceptSource(AuthorAccess authorAccess, int source) { + if (source == DND_EXTERNAL) { + // Accept only from external source + return true; + } + // For urls from other sources (Dita Maps Manager, Project) a new tab will be open. + return false; + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorExternalObjectInsertionHandler#acceptURLs(ro.sync.ecss.extensions.api.AuthorAccess, java.util.List, int) + */ + @Override + public boolean acceptURLs(AuthorAccess authorAccess, List urls, int source) { + boolean accept = acceptSource(authorAccess, source); + if (accept) { + for (int i = 0; i < urls.size(); i++) { + // Accept only XML and image files + if (!authorAccess.getUtilAccess().isSupportedImageURL(urls.get(i)) && + !"xml".equalsIgnoreCase(URLUtil.getExtension(urls.get(i).toString()))) { + accept = false; + break; + } + } + } + return accept; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFReferencesResolver.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFReferencesResolver.java new file mode 100644 index 0000000..0c1cbb4 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFReferencesResolver.java @@ -0,0 +1,199 @@ +package simple.documentation.framework.extensions; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.xml.transform.sax.SAXSource; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorReferenceResolver; +import ro.sync.ecss.extensions.api.node.AttrValue; +import ro.sync.ecss.extensions.api.node.AuthorElement; +import ro.sync.ecss.extensions.api.node.AuthorNode; + +/** + * References resolver for Simple Documentation Framework. + * + */ +public class SDFReferencesResolver implements AuthorReferenceResolver { + /** + * Logger for logging. + */ + private static Logger logger = LogManager.getLogger( + SDFReferencesResolver.class.getName()); + + /** + * Verifies if the handler considers the node to have references. + * + * @param node The node to be analyzed. + * @return true 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: + * + *
      + *
    • Resources that are already opened in editor. + * For this case the InputSource will contains the editor content.
    • + *
    • Resources resolved through XML catalog.
    • + *
    + * + * @return The SAX source including the parser and the parser's input source. + */ + public SAXSource resolveReference( + AuthorNode node, + String systemID, + AuthorAccess authorAccess, + EntityResolver entityResolver) { + SAXSource saxSource = null; + if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) { + AuthorElement element = (AuthorElement) node; + if ("ref".equals(element.getLocalName())) { + AttrValue attrValue = element.getAttribute("location"); + if (attrValue != null){ + String attrStringVal = attrValue.getValue(); + if (attrStringVal.length() > 0) { + try { + URL absoluteUrl = new URL(new URL(systemID), + authorAccess.getUtilAccess().correctURL(attrStringVal)); + InputSource inputSource = entityResolver.resolveEntity(null, + absoluteUrl.toString()); + if(inputSource == null) { + inputSource = new InputSource(absoluteUrl.toString()); + } + XMLReader xmlReader = authorAccess.getXMLUtilAccess().newNonValidatingXMLReader(); + xmlReader.setEntityResolver(entityResolver); + saxSource = new SAXSource(xmlReader, inputSource); + } catch (MalformedURLException e) { + logger.error(e, e); + } catch (SAXException e) { + logger.error(e, e); + } catch (IOException e) { + logger.error(e, e); + } + } + } + } + } + return saxSource; + } + + /** + * Get an unique identifier for the node reference. + * + * The unique identifier is used to avoid resolving the references + * recursively. + * + * @param node The node that has reference. + * @return An unique identifier for the reference node. + */ + public String getReferenceUniqueID(AuthorNode node) { + String id = null; + if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) { + AuthorElement element = (AuthorElement) node; + if ("ref".equals(element.getLocalName())) { + AttrValue attrValue = element.getAttribute("location"); + if (attrValue != null) { + id = attrValue.getValue(); + } + } + } + return id; + } + + /** + * Return the systemID of the referred content. + * + * @param node The reference node. + * @param authorAccess The author access. + * + * @return The systemID of the referred content. + */ + public String getReferenceSystemID(AuthorNode node, + AuthorAccess authorAccess) { + String systemID = null; + if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) { + AuthorElement element = (AuthorElement) node; + if ("ref".equals(element.getLocalName())) { + AttrValue attrValue = element.getAttribute("location"); + if (attrValue != null) { + String attrStringVal = attrValue.getValue(); + try { + URL absoluteUrl = new URL(node.getXMLBaseURL(), + authorAccess.getUtilAccess().correctURL(attrStringVal)); + systemID = absoluteUrl.toString(); + } catch (MalformedURLException e) { + logger.error(e, e); + } + } + } + } + return systemID; + } + + /** + * Verifies if the references of the given node must be refreshed + * when the attribute with the specified name has changed. + * + * @param node The node with the references. + * @param attributeName The name of the changed attribute. + * @return 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, List nodesToJoin, AuthorAccess authorAccess) + throws InvalidEditException { + // Not handled. + return false; + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorSchemaAwareEditingHandler#handlePasteFragment(int, ro.sync.ecss.extensions.api.node.AuthorDocumentFragment[], int, ro.sync.ecss.extensions.api.AuthorAccess) + */ + @Override + public boolean handlePasteFragment(int offset, AuthorDocumentFragment[] fragmentsToInsert, int actionId, + AuthorAccess authorAccess) throws InvalidEditException { + boolean handleInsertionEvent = false; + AuthorSchemaManager authorSchemaManager = authorAccess.getDocumentController().getAuthorSchemaManager(); + if (!authorSchemaManager.isLearnSchema() && + !authorSchemaManager.hasLoadingErrors() && + authorSchemaManager.getAuthorSchemaAwareOptions().isEnableSmartPaste()) { + handleInsertionEvent = handleInsertionEvent(offset, fragmentsToInsert, authorAccess); + } + return handleInsertionEvent; + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorSchemaAwareEditingHandler#handleTyping(int, char, ro.sync.ecss.extensions.api.AuthorAccess) + */ + @Override + public boolean handleTyping(int offset, char ch, AuthorAccess authorAccess) + throws InvalidEditException { + boolean handleTyping = false; + AuthorSchemaManager authorSchemaManager = authorAccess.getDocumentController().getAuthorSchemaManager(); + if (!authorSchemaManager.isLearnSchema() && + !authorSchemaManager.hasLoadingErrors() && + authorSchemaManager.getAuthorSchemaAwareOptions().isEnableSmartTyping()) { + try { + AuthorDocumentFragment characterFragment = + authorAccess.getDocumentController().createNewDocumentTextFragment(String.valueOf(ch)); + handleTyping = handleInsertionEvent(offset, new AuthorDocumentFragment[] {characterFragment}, authorAccess); + } catch (AuthorOperationException e) { + throw new InvalidEditException(e.getMessage(), "Invalid typing event: " + e.getMessage(), e, false); + } + } + return handleTyping; + } + + /** + * Handle an insertion event (either typing or paste). + * + * @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. + * + * @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("/>"); + 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(""); + // 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. + List contentNodes = sectionElement.getContentNodes(); + if (contentNodes.size() == 1) { + AuthorNode child = contentNodes.get(0); + boolean isTitleChild = isElementWithNameAndNamespace(child, TITLE); + if (isTitleChild && child.getEndOffset() < offset) { + // We are after the title. + + // Empty sect element + WhatElementsCanGoHereContext context = authorSchemaManager.createWhatElementsCanGoHereContext(offset); + // Derive the context by adding a para + pushContextElement(context, PARA); + + // Test if fragments can be inserted in 'para' element + if (authorSchemaManager.canInsertDocumentFragments( + fragmentsToInsert, + context, + AuthorSchemaManager.VALIDATION_MODE_STRICT_FIRST_CHILD_LAX_OTHERS)) { + // Create a para structure and insert fragments inside + StringBuilder xmlFragment = new StringBuilder("<").append(PARA); + if (SDF_NAMESPACE != null && SDF_NAMESPACE.length() != 0) { + xmlFragment.append(" xmlns=\"").append(SDF_NAMESPACE).append("\""); + } + xmlFragment.append(">").append(""); + // Insert para + 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; + } + } + } + } + return handleEvent; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFSchemaManagerFilter.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFSchemaManagerFilter.java new file mode 100644 index 0000000..645e4b8 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFSchemaManagerFilter.java @@ -0,0 +1,142 @@ +package simple.documentation.framework.extensions; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; + +import ro.sync.contentcompletion.xml.CIAttribute; +import ro.sync.contentcompletion.xml.CIElement; +import ro.sync.contentcompletion.xml.CIValue; +import ro.sync.contentcompletion.xml.Context; +import ro.sync.contentcompletion.xml.ContextElement; +import ro.sync.contentcompletion.xml.SchemaManagerFilter; +import ro.sync.contentcompletion.xml.WhatAttributesCanGoHereContext; +import ro.sync.contentcompletion.xml.WhatElementsCanGoHereContext; +import ro.sync.contentcompletion.xml.WhatPossibleValuesHasAttributeContext; +import simple.documentation.framework.SDFElement; + +/** + * Schema manager filter for the Simple Documentation Framework. + * Filters custom elements, attributes, elements values and attributes values. + * + */ +public class SDFSchemaManagerFilter implements SchemaManagerFilter { + + /** + * Filter values of the "href" attribute of an image element. + */ + public List filterAttributeValues(List attributeValues, + WhatPossibleValuesHasAttributeContext context) { + // If the element from the current context is the "image" element and the current context + // attribute is "href" then add a custom URL value to the list of default content completion + // proposals. + if (context != null) { + ContextElement currentElement = context.getParentElement(); + String attributeName = context.getAttributeName(); + if("image".equals(currentElement.getQName()) && "href".equals(attributeName)) { + CIValue newValue = new CIValue("Custom_image_URL"); + if (attributeValues == null) { + attributeValues = new ArrayList(); + } + // Add the new value. + attributeValues.add(newValue); + } + } + return attributeValues; + } + + /** + * Filter attributes of the "table" element. + */ + public List filterAttributes(List attributes, + WhatAttributesCanGoHereContext context) { + // If the element from the current context is the 'table' element add the + // attribute named 'frame' to the list of default content completion proposals + if (context != null) { + ContextElement contextElement = context.getParentElement(); + if ("table".equals(contextElement.getQName())) { + CIAttribute frameAttribute = new CIAttribute(); + frameAttribute.setName("frame"); + frameAttribute.setRequired(false); + frameAttribute.setFixed(false); + frameAttribute.setDefaultValue("void"); + if (attributes == null) { + attributes = new ArrayList(); + } + attributes.add(frameAttribute); + } + } + return attributes; + } + + /** + * Filter the value of the "title" element from the "section". + */ + public List filterElementValues(List elementValues, + Context context) { + // If the element from the current context is the title of the section element then add the + // "Custom Section Title" value to the list of default content completion proposals + if (context != null) { + Stack elementStack = context.getElementStack(); + if (elementStack != null) { + ContextElement contextElement = elementStack.peek(); + if(contextElement != null) { + int size = elementStack.size(); + if ("title".equals(contextElement.getQName())) { + ContextElement parentElement = elementStack.elementAt(size - 2); + if (parentElement != null && "section".equals(parentElement.getQName())) { + elementValues = new ArrayList(); + CIValue val = new CIValue("Custom Section Title"); + elementValues.add(val); + } + } + } + } + } + return elementValues; + } + + /** + * Filter "header" elements. + */ + public List filterElements(List elements, + WhatElementsCanGoHereContext context) { + // If the element from the current context is the 'header' element remove the + // 'td' element from the list of content completion proposals and add the + // 'th' element. + if (context != null) { + Stack elementStack = context.getElementStack(); + if (elementStack != null) { + ContextElement contextElement = context.getElementStack().peek(); + if ("header".equals(contextElement.getQName())) { + if (elements != null) { + for (Iterator iterator = elements.iterator(); iterator.hasNext();) { + CIElement element = iterator.next(); + // Remove the 'td' element + if ("td".equals(element.getQName())) { + elements.remove(element); + break; + } + } + } else { + elements = new ArrayList(); + } + // Insert the 'th' element in the list of content completion proposals + CIElement thElement = new SDFElement(); + thElement.setName("th"); + elements.add(thElement); + } + } + } else { + // If the given context is null then the given list of content completion elements contains + // global elements. + } + return elements; + } + + public String getDescription() { + return "Implementation for the Simple Documentation Framework schema manager filter."; + } + +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFStylesFilter.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFStylesFilter.java new file mode 100644 index 0000000..c34e964 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/SDFStylesFilter.java @@ -0,0 +1,139 @@ +package simple.documentation.framework.extensions; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import ro.sync.ecss.css.EditorContent; +import ro.sync.ecss.css.LabelContent; +import ro.sync.ecss.css.StaticContent; +import ro.sync.ecss.css.Styles; +import ro.sync.ecss.extensions.api.StylesFilter; +import ro.sync.ecss.extensions.api.editor.InplaceEditorArgumentKeys; +import ro.sync.ecss.extensions.api.node.AuthorNode; + +/** + * + * Style Filter for Simple Documentation Framework. + * + */ +public class SDFStylesFilter implements StylesFilter { + + /** + * Filter the style of "para", "b" and "i" elements. + */ + public Styles filter(Styles styles, AuthorNode authorNode) { + //Use fixed font size of 12 for "para". + if(authorNode.getName().equals("para")) { + ro.sync.exml.view.graphics.Font original = styles.getFont(); + ro.sync.exml.view.graphics.Font modified = new ro.sync.exml.view.graphics.Font( + original.getName(), original.getStyle(), 12); + styles.setProperty(Styles.KEY_FONT, modified); + } + + //Use foreground color red for "b" + if(authorNode.getName().equals("b")) { + ro.sync.exml.view.graphics.Color red = ro.sync.exml.view.graphics.Color.COLOR_RED; + styles.setProperty(Styles.KEY_FOREGROUND_COLOR, red); + } + + //Use left border width of 5 pixels for "i" + if(authorNode.getName().equals("i")) { + styles.setProperty(Styles.KEY_BORDER_LEFT_WIDTH, new Integer(5)); + } + + if(authorNode.getType() == AuthorNode.NODE_TYPE_PSEUDO_ELEMENT + && "before".equals(authorNode.getName())) { + authorNode = authorNode.getParent(); + if ("country".equals(authorNode.getName())) { + // This is the BEFORE pseudo element of the "country" element. + // Read the supported countries from the configuration file. + // This will be a comma separated enumeration: France, Spain, Great Britain + String countries = readCountriesFromFile(); + Map formControlArgs = new HashMap(); + formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_EDIT_QUALIFIED, "#text"); + formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_TYPE, InplaceEditorArgumentKeys.TYPE_COMBOBOX); + formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_VALUES, countries); + formControlArgs.put(InplaceEditorArgumentKeys.PROPERTY_EDITABLE, "false"); + + // We also add a label in form of the form control. + Map labelProps = new HashMap(); + labelProps.put("text", "Country: "); + labelProps.put("styles", "* {width: 100px; color: gray;}"); + StaticContent[] mixedContent = new StaticContent[] {new LabelContent(labelProps), new EditorContent(formControlArgs)}; + styles.setProperty(Styles.KEY_MIXED_CONTENT, mixedContent); + } + } + + // The previously added form control is the only way the element can be edited. + if ("country".equals(authorNode.getName())) { + styles.setProperty(Styles.KEY_VISIBITY, "-oxy-collapse-text"); + } + + return styles; + } + + /** + * The filter is invoked every time the styles are needed so we will make sure + * we load the countries only once. + */ + private String countries = null; + + /** + * Read the available countries from the configuration file. + * + * @return The supported countries, read from the configuration file. + * This will be a comma separated enumeration: France, Spain, Great Britain. + */ + private String readCountriesFromFile() { + if (countries == null) { + StringBuilder countriesBuilder = new StringBuilder(); + // Our countries file is located in the framework folder. To compute + // the framework location we will use the fact that the JAR this class is in + // is located inside the framework folder. + String classLocation = "/" + getClass().getCanonicalName().replace(".", "/") + ".class"; + URL resource = getClass().getResource(classLocation); + + if (resource != null) { + // The URL for the class looks like this: + // jar:file:/D:/projects/eXml/frameworks/sdf/sdf.jar!/simple/documentation/framework/extensions/SDFStylesFilter.class + String jarURL = resource.toString(); + // This is the URL of the JAR form where the class was loaded. + jarURL = jarURL.substring(jarURL.indexOf(":") + 1, jarURL.indexOf("!/")); + + try { + // We know the resources are next to the JAR. + URL resourceFile = new URL(new URL(jarURL), "resources/countries.txt"); + InputStream openStream = resourceFile.openStream(); + try { + InputStreamReader inputStreamReader = new InputStreamReader(openStream, "UTF8"); + char[] cbuf = new char[1024]; + int length = -1; + while ((length = inputStreamReader.read(cbuf)) != -1) { + countriesBuilder.append(cbuf, 0, length); + } + } finally { + openStream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + countries = countriesBuilder.toString(); + } + + return countries; + } + + /** + * Description. + */ + public String getDescription() { + return "Implementation for the Simple Documentation Framework style filter."; + } +} + diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/TableCellSpanProvider.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/TableCellSpanProvider.java new file mode 100644 index 0000000..b5b4126 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/extensions/TableCellSpanProvider.java @@ -0,0 +1,74 @@ +package simple.documentation.framework.extensions; + +import ro.sync.ecss.extensions.api.AuthorTableCellSpanProvider; +import ro.sync.ecss.extensions.api.node.AttrValue; +import ro.sync.ecss.extensions.api.node.AuthorElement; + +/** + * Simple Documentation Framework table cell span provider. + * + */ +public class TableCellSpanProvider implements AuthorTableCellSpanProvider { + + /** + * Extracts the integer specifying what is the width (in columns) of the cell + * representing in the table layout the cell element. + */ + public Integer getColSpan(AuthorElement cell) { + Integer colSpan = null; + + AttrValue attrValue = cell.getAttribute("column_span"); + if(attrValue != null) { + // The attribute was found. + String cs = attrValue.getValue(); + if(cs != null) { + try { + colSpan = new Integer(cs); + } catch (NumberFormatException ex) { + // The attribute value was not a number. + } + } + } + return colSpan; + } + + /** + * Extracts the integer specifying what is the height (in rows) of the cell + * representing in the table layout the cell element. + */ + public Integer getRowSpan(AuthorElement cell) { + Integer rowSpan = null; + + AttrValue attrValue = cell.getAttribute("row_span"); + if(attrValue != null) { + // The attribute was found. + String rs = attrValue.getValue(); + if(rs != null) { + try { + rowSpan = new Integer(rs); + } catch (NumberFormatException ex) { + // The attribute value was not a number. + } + } + } + return rowSpan; + } + + /** + * @return true considering the column specifications always available. + */ + public boolean hasColumnSpecifications(AuthorElement tableElement) { + return true; + } + + /** + * Ignored. We do not extract data from the table 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 List colWidthSpecs = new ArrayList(); + + /** + * The table element + */ + private AuthorElement tableElement; + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#commitColumnWidthModifications(ro.sync.ecss.extensions.api.AuthorDocumentController, ro.sync.ecss.extensions.api.WidthRepresentation[], java.lang.String) + */ + public void commitColumnWidthModifications(AuthorDocumentController authorDocumentController, + WidthRepresentation[] colWidths, String tableCellsTagName) throws AuthorOperationException { + if ("td".equals(tableCellsTagName)) { + if (colWidths != null && tableElement != null) { + if (colsStartOffset >= 0 && colsEndOffset >= 0 && colsStartOffset < colsEndOffset) { + authorDocumentController.delete(colsStartOffset, + colsEndOffset); + } + String xmlFragment = createXMLFragment(colWidths); + int offset = -1; + AuthorElement[] header = tableElement.getElementsByLocalName("header"); + if (header != null && header.length > 0) { + // Insert the cols elements before the 'header' element + offset = header[0].getStartOffset(); + } else { + AuthorElement[] title = tableElement.getElementsByLocalName("title"); + if (title != null && title.length > 0) { + // Insert the cols elements after the 'title' element + offset = title[0].getStartOffset() + 1; + } else { + // Just insert after table start tag + offset = tableElement.getStartOffset() + 1; + } + } + if (offset == -1) { + throw new AuthorOperationException("No valid offset to insert the columns width specification."); + } + authorDocumentController.insertXMLFragment(xmlFragment, offset); + } + } + } + + /** + * Creates the XML fragment representing the column specifications. + * + * @param widthRepresentations + * @return The XML fragment as a string. + */ + private String createXMLFragment(WidthRepresentation[] widthRepresentations) { + StringBuffer fragment = new StringBuffer(); + String ns = tableElement.getNamespace(); + for (int i = 0; i < widthRepresentations.length; i++) { + WidthRepresentation width = widthRepresentations[i]; + fragment.append(" 0) { + fragment.append(" xmlns=\"" + ns + "\""); + } + fragment.append("/>"); + } + return fragment.toString(); + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#commitTableWidthModification(ro.sync.ecss.extensions.api.AuthorDocumentController, int, java.lang.String) + */ + public void commitTableWidthModification(AuthorDocumentController authorDocumentController, + int newTableWidth, String tableCellsTagName) throws AuthorOperationException { + if ("td".equals(tableCellsTagName)) { + if (newTableWidth > 0) { + if (tableElement != null) { + String newWidth = String.valueOf(newTableWidth); + + authorDocumentController.setAttribute( + "width", + new AttrValue(newWidth), + tableElement); + } else { + throw new AuthorOperationException("Cannot find the element representing the table."); + } + } + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#getCellWidth(ro.sync.ecss.extensions.api.node.AuthorElement, int, int) + */ + public List getCellWidth(AuthorElement cellElement, int colNumberStart, + int colSpan) { + List toReturn = null; + int size = colWidthSpecs.size(); + if (size >= colNumberStart && size >= colNumberStart + colSpan) { + toReturn = new ArrayList(colSpan); + for (int i = colNumberStart; i < colNumberStart + colSpan; i ++) { + // Add the column widths + toReturn.add(colWidthSpecs.get(i)); + } + } + return toReturn; + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#getTableWidth(java.lang.String) + */ + public WidthRepresentation getTableWidth(String tableCellsTagName) { + WidthRepresentation toReturn = null; + if (tableElement != null && "td".equals(tableCellsTagName)) { + AttrValue widthAttr = tableElement.getAttribute("width"); + if (widthAttr != null) { + String width = widthAttr.getValue(); + if (width != null) { + toReturn = new WidthRepresentation(width, true); + } + } + } + return toReturn; + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#init(ro.sync.ecss.extensions.api.node.AuthorElement) + */ + public void init(AuthorElement tableElement) { + this.tableElement = tableElement; + AuthorElement[] colChildren = tableElement.getElementsByLocalName("customcol"); + if (colChildren != null && colChildren.length > 0) { + for (int i = 0; i < colChildren.length; i++) { + AuthorElement colChild = colChildren[i]; + if (i == 0) { + colsStartOffset = colChild.getStartOffset(); + } + if (i == colChildren.length - 1) { + colsEndOffset = colChild.getEndOffset(); + } + // Determine the 'width' for this col. + AttrValue colWidthAttribute = colChild.getAttribute("width"); + String colWidth = null; + if (colWidthAttribute != null) { + colWidth = colWidthAttribute.getValue(); + // Add WidthRepresentation objects for the columns this 'customcol' specification + // spans over. + colWidthSpecs.add(new WidthRepresentation(colWidth, true)); + } + } + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#isAcceptingFixedColumnWidths(java.lang.String) + */ + public boolean isAcceptingFixedColumnWidths(String tableCellsTagName) { + return "td".equals(tableCellsTagName); + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#isAcceptingPercentageColumnWidths(java.lang.String) + */ + public boolean isAcceptingPercentageColumnWidths(String tableCellsTagName) { + return "td".equals(tableCellsTagName); + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#isAcceptingProportionalColumnWidths(java.lang.String) + */ + public boolean isAcceptingProportionalColumnWidths(String tableCellsTagName) { + return "td".equals(tableCellsTagName); + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#isTableAcceptingWidth(java.lang.String) + */ + public boolean isTableAcceptingWidth(String tableCellsTagName) { + return "td".equals(tableCellsTagName); + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider#isTableAndColumnsResizable(java.lang.String) + */ + public boolean isTableAndColumnsResizable(String tableCellsTagName) { + return "td".equals(tableCellsTagName); + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + 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/filters/SDFDocumentFilter.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/filters/SDFDocumentFilter.java new file mode 100644 index 0000000..f4c986a --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/filters/SDFDocumentFilter.java @@ -0,0 +1,104 @@ +package simple.documentation.framework.filters; + +import javax.swing.text.BadLocationException; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorDocumentFilter; +import ro.sync.ecss.extensions.api.AuthorDocumentFilterBypass; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.node.AuthorElement; +import ro.sync.ecss.extensions.api.node.AuthorNode; + +/** + * Simple Documentation Framework document filter used to restrict insertion and deletion of + * different nodes from the document when the strict mode is activated. + * + */ +public class SDFDocumentFilter extends AuthorDocumentFilter { + + /** + * The author access. + */ + private final AuthorAccess authorAccess; + + /** + * Constructor. + * + * @param access The author access. + */ + public SDFDocumentFilter(AuthorAccess access) { + this.authorAccess = access; + } + + /** + * Check if the strict mode is activated + * @return True 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("", caretOffset, caretOffset + toInsert.length() - 1); + authorAccess.getEditorAccess().setCaretPosition(caretOffset + toInsert.length() + 1); + } catch (AuthorOperationException e) { + e.printStackTrace(); + } + } + } + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorCaretListener.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorCaretListener.java new file mode 100644 index 0000000..91090e4 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorCaretListener.java @@ -0,0 +1,76 @@ +package simple.documentation.framework.listeners; + +import javax.swing.text.BadLocationException; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorCaretEvent; +import ro.sync.ecss.extensions.api.AuthorCaretListener; +import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment; +import ro.sync.ecss.extensions.api.node.AuthorElement; +import ro.sync.ecss.extensions.api.node.AuthorNode; +import ro.sync.exml.view.graphics.Rectangle; +import ro.sync.exml.workspace.api.Platform; +import simple.documentation.framework.ui.SDFPopupWindow; + +/** + * Author caret listener used to display the XML fragment corresponding to a para element + * found at the caret position. + * + */ +public class SDFAuthorCaretListener implements AuthorCaretListener { + + /** + * Access to the author specific functions. + */ + private AuthorAccess authorAcess; + + /** + * The popup used to display the XML fragment. + */ + private SDFPopupWindow popupWindow; + + /** + * Constructor. + * + * @param authorAccess Access to the author specific functions. + */ + public SDFAuthorCaretListener(AuthorAccess authorAccess) { + this.authorAcess = authorAccess; + // Use the information popup only if this is the standalone Oxygen version. + if (authorAccess.getWorkspaceAccess().getPlatform() == Platform.STANDALONE) { + // Create the information popup window. + popupWindow = new SDFPopupWindow(authorAccess, "XML Fragment:"); + } + } + + /** + * Caret moved. + * Display the XML fragment corresponding to a para element found at the caret + * position in a popup window. + */ + public void caretMoved(AuthorCaretEvent caretEvent) { + // Verify if the node corresponding to the new caret position corresponds to a "para" element. + if (authorAcess.getWorkspaceAccess().getPlatform() == Platform.STANDALONE) { + int caretOffset = authorAcess.getEditorAccess().getCaretOffset(); + try { + AuthorNode nodeAtOffset = authorAcess.getDocumentController().getNodeAtOffset(caretOffset); + if (nodeAtOffset != null && nodeAtOffset instanceof AuthorElement) { + AuthorElement element = (AuthorElement) nodeAtOffset; + if ("para".equals(element.getLocalName())) { + AuthorDocumentFragment paraFragment = authorAcess.getDocumentController().createDocumentFragment(element, true); + String serializeFragmentToXML = authorAcess.getDocumentController().serializeFragmentToXML(paraFragment); + // Find the x and y coordinates from the caret shape (the popup window location). + Rectangle modelToView = authorAcess.getEditorAccess().modelToViewRectangle(authorAcess.getEditorAccess().getCaretOffset()); + popupWindow.setTimeToDisplay(3); + popupWindow.display( + serializeFragmentToXML, + modelToView.x + modelToView.width, + modelToView.y + modelToView.height, + 10); + } + } + } catch (BadLocationException e) { + } + } + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorListener.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorListener.java new file mode 100644 index 0000000..e955b24 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorListener.java @@ -0,0 +1,130 @@ +package simple.documentation.framework.listeners; + +import java.util.List; + +import ro.sync.ecss.extensions.api.AttributeChangedEvent; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorListenerAdapter; +import ro.sync.ecss.extensions.api.DocumentContentDeletedEvent; +import ro.sync.ecss.extensions.api.DocumentContentInsertedEvent; +import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment; +import ro.sync.ecss.extensions.api.node.AuthorElement; +import ro.sync.ecss.extensions.api.node.AuthorNode; + +/** + * Simple Documentation Framework Author listener. + */ +public class SDFAuthorListener extends AuthorListenerAdapter { + + /** + * Access to the author specific functions. + */ + private AuthorAccess authorAccess; + + /** + * Constructor. + * + * @param authorAccess Access to the author specific functions + */ + public SDFAuthorListener(AuthorAccess authorAccess) { + this.authorAccess = authorAccess; + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorListenerAdapter#attributeChanged(ro.sync.ecss.extensions.api.AttributeChangedEvent) + */ + @Override + public void attributeChanged(AttributeChangedEvent e) { + String strictMode = authorAccess.getOptionsStorage().getOption("strictMode", "false"); + if ("true".equals(strictMode)) { + // If the changed attribute is the "column_span" or "row_span" attribute of the "td" + // element then verify if the new value is an integer value + AuthorNode ownerAuthorNode = e.getOwnerAuthorNode(); + if (ownerAuthorNode instanceof AuthorElement) { + AuthorElement ownerAuthorElement = (AuthorElement) ownerAuthorNode; + if ("td".equals(ownerAuthorElement.getLocalName())) { + String attributeName = e.getAttributeName(); + if ("column_span".equals(attributeName) || "row_span".equals(attributeName)) { + String spanValue = ownerAuthorElement.getAttribute(attributeName).getValue(); + try { + Integer.parseInt(spanValue); + } catch (NumberFormatException ex) { + authorAccess.getWorkspaceAccess().showInformationMessage("The value " + spanValue + " of attribute " + attributeName + + " is not valid."); + } + } + } + } + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorListenerAdapter#beforeContentDelete(ro.sync.ecss.extensions.api.DocumentContentDeletedEvent) + */ + @Override + public void beforeContentDelete(DocumentContentDeletedEvent deleteEvent) { + String strictMode = authorAccess.getOptionsStorage().getOption("strictMode", "false"); + if ("true".equals(strictMode)) { + // If the section title is deleted an error message will inform the user that the title + // is required. + if (deleteEvent.getType() != DocumentContentDeletedEvent.INSERT_TEXT_EVENT + && deleteEvent.getType() != DocumentContentDeletedEvent.DELETE_TEXT_EVENT) { + AuthorNode changedNode = deleteEvent.getParentNode(); + if (changedNode instanceof AuthorElement) { + AuthorElement changedElement = (AuthorElement) changedNode; + // Section element + if ("section".equals(changedElement.getLocalName())) { + AuthorElement[] titleElements = changedElement.getElementsByLocalName("title"); + // If the section has one "title" child element + if (titleElements.length == 1) { + // Find if the deleted element is the "title" one. + AuthorDocumentFragment deletedFragment = deleteEvent.getDeletedFragment(); + List contentNodes = deletedFragment.getContentNodes(); + for (AuthorNode authorNode : contentNodes) { + if (authorNode instanceof AuthorElement) { + if ("title".equals(((AuthorElement)authorNode).getLocalName())) { + String errorMessage = "The section must have a title."; + authorAccess.getWorkspaceAccess().showErrorMessage(errorMessage); + } + } + } + } + } + } + } + } + super.beforeContentDelete(deleteEvent); + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorListenerAdapter#contentInserted(ro.sync.ecss.extensions.api.DocumentContentInsertedEvent) + */ + @Override + public void contentInserted(DocumentContentInsertedEvent e) { + AuthorNode node = e.getParentNode(); + AuthorNode parentNode = node.getParent(); + // For 'section' nodes the title text is rendered in the Outline + // (see customizeRenderingInformation method from SDFAuthorOutlineCustomizer) + // so we need to refresh the section node from the Outline when the title + // text has changed. + if ("title".equals(node.getName()) && "section".equals(parentNode.getName())) { + authorAccess.getOutlineAccess().refreshNodes(new AuthorNode[] {parentNode}); + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorListenerAdapter#contentDeleted(ro.sync.ecss.extensions.api.DocumentContentDeletedEvent) + */ + @Override + public void contentDeleted(DocumentContentDeletedEvent e) { + AuthorNode node = e.getParentNode(); + AuthorNode parentNode = node.getParent(); + // For 'section' nodes the title text is rendered in the Outline + // (see customizeRenderingInformation method from SDFAuthorOutlineCustomizer) + // so we need to refresh the section node from the Outline when the title + // text has changed. + if ("title".equals(node.getName()) && "section".equals(parentNode.getName())) { + authorAccess.getOutlineAccess().refreshNodes(new AuthorNode[] {parentNode}); + } + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorMouseListener.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorMouseListener.java new file mode 100644 index 0000000..9db5685 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/listeners/SDFAuthorMouseListener.java @@ -0,0 +1,62 @@ +package simple.documentation.framework.listeners; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorMouseEvent; +import ro.sync.ecss.extensions.api.AuthorMouseListener; +import ro.sync.exml.workspace.api.Platform; +import simple.documentation.framework.ui.SDFPopupWindow; + +/** + * Custom author mouse listener used to display the mouse coordinates in a popup window + * on mouse clicked. + * + */ +public class SDFAuthorMouseListener implements AuthorMouseListener { + + /** + * Access to the author specific functions. + */ + private AuthorAccess authorAccess; + + /** + * The popup used to display the mouse coordinates. + */ + private SDFPopupWindow popupWindow; + + /** + * Constructor. + * + * @param authorAccess Access to the author specific functions + */ + public SDFAuthorMouseListener(AuthorAccess authorAccess) { + this.authorAccess = authorAccess; + // Use the information popup only if this is the standalone Oxygen version. + if (authorAccess.getWorkspaceAccess().getPlatform() == Platform.STANDALONE) { + popupWindow = new SDFPopupWindow(authorAccess, "Position"); + } + } + + + public void mouseClicked(AuthorMouseEvent e) { + // Display the mouse coordinates. + if (authorAccess.getWorkspaceAccess().getPlatform() == Platform.STANDALONE) { + if (e.clickCount == 2) { + String toDisplay = "X: " + e.X + " Y: " + e.Y; + popupWindow.setTimeToDisplay(2); + popupWindow.display(toDisplay, e.X, e.Y, 10); + } + } + } + + public void mousePressed(AuthorMouseEvent e) { + } + + public void mouseReleased(AuthorMouseEvent e) { + } + + public void mouseDragged(AuthorMouseEvent e) { + } + + public void mouseMoved(AuthorMouseEvent e) { + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/ExtractNodeToFileOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/ExtractNodeToFileOperation.java new file mode 100644 index 0000000..e01f2a2 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/ExtractNodeToFileOperation.java @@ -0,0 +1,76 @@ +package simple.documentation.framework.operations; + +import java.awt.Component; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.net.URL; + +import javax.swing.JFileChooser; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment; +import ro.sync.ecss.extensions.api.node.AuthorNode; +import ro.sync.basic.util.URLUtil; + +/** + * Operation to save the Author node at caret in a separate document and refresh the new file path in the project. + */ +public class ExtractNodeToFileOperation implements AuthorOperation { + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + public void doOperation(AuthorAccess authorAccess, ArgumentsMap args) throws IllegalArgumentException, + AuthorOperationException { + int caretOffset = authorAccess.getEditorAccess().getCaretOffset(); + try { + // Get node at caret + AuthorNode nodeAtCaret = authorAccess.getDocumentController().getNodeAtOffset(caretOffset); + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setMultiSelectionEnabled(false); + + // Show Save Dialog + if (fileChooser.showSaveDialog((Component) authorAccess.getWorkspaceAccess().getParentFrame()) + == JFileChooser.APPROVE_OPTION) { + File outputFile = fileChooser.getSelectedFile(); + FileOutputStream fos = new FileOutputStream(outputFile); + OutputStreamWriter writer = new OutputStreamWriter(fos, "UTF-8"); + + // Write the node fragment + AuthorDocumentFragment fragment = authorAccess.getDocumentController().createDocumentFragment(nodeAtCaret, true); + String xmlFragment = authorAccess.getDocumentController().serializeFragmentToXML(fragment); + writer.write(xmlFragment); + writer.close(); + + // Open file + URL outputFileUrl = URLUtil.correct(outputFile); + authorAccess.getWorkspaceAccess().open(outputFileUrl); + + // Refresh in project + authorAccess.getWorkspaceAccess().refreshInProject(outputFileUrl); + } + } catch (Exception e) { + authorAccess.getWorkspaceAccess().showErrorMessage(e.getMessage()); + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Save the Author node at caret in a separate document and refresh the new file path in the project"; + } + +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/InsertElementOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/InsertElementOperation.java new file mode 100644 index 0000000..760e69f --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/InsertElementOperation.java @@ -0,0 +1,127 @@ +package simple.documentation.framework.operations; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.event.ActionEvent; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.JFrame; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import javax.swing.text.BadLocationException; + +import ro.sync.contentcompletion.xml.CIElement; +import ro.sync.contentcompletion.xml.WhatElementsCanGoHereContext; +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.AuthorSchemaManager; +import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment; +import ro.sync.exml.view.graphics.Point; +import ro.sync.exml.view.graphics.Rectangle; + +/** + * Show a popup menu that contains the name of all elements that can be inserted at the caret offset. + */ +public class InsertElementOperation implements AuthorOperation { + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + @SuppressWarnings("serial") + public void doOperation(final AuthorAccess authorAccess, ArgumentsMap args) + throws IllegalArgumentException, AuthorOperationException { + try { + //Get the caret offset + final int caretOffset = authorAccess.getEditorAccess().getCaretOffset(); + //The schema manager + final AuthorSchemaManager schemaManager = authorAccess.getDocumentController().getAuthorSchemaManager(); + //The context of elements. + WhatElementsCanGoHereContext ctxt = schemaManager.createWhatElementsCanGoHereContext(caretOffset); + //Get the list of elements which can be inserted here + final List childrenElements = schemaManager.getChildrenElements(ctxt); + JPopupMenu jpo = new JPopupMenu(); + for (int i = 0; i < childrenElements.size(); i++) { + final int index = i; + jpo.add(new JMenuItem(new AbstractAction(childrenElements.get(index).getName()) { + public void actionPerformed(ActionEvent e) { + CIElement toInsert = childrenElements.get(index); + try { + //The CIElement contains all data necessary to make a small XML fragment with + //the string to insert and then call + // authorAccess.getDocumentController().createNewDocumentFragmentInContext(xmlFragment, caretOffset); + //But Oxygen 11.2 will come with a easier method: + //Create a document fragment from the CIElement. + AuthorDocumentFragment frag = schemaManager.createAuthorDocumentFragment(toInsert); + //Now you can process the fragment and remove/add attributes. + authorAccess.getDocumentController().insertFragment(caretOffset, frag); + } catch (BadLocationException e1) { + e1.printStackTrace(); + } + } + })); + } + Rectangle mtv = authorAccess.getEditorAccess().modelToViewRectangle(caretOffset); + Point popupLocation = authorAccess.getEditorAccess().getLocationOnScreenAsPoint(mtv.x, mtv.y); + jpo.setLocation(popupLocation.x, popupLocation.y); + JFrame oxygenFrame = (JFrame)authorAccess.getWorkspaceAccess().getParentFrame(); + + // Get the author component + JPanel authorComponent = (JPanel)authorAccess.getEditorAccess().getAuthorComponent(); + // Get the glass pane + final Component glassPane = authorComponent.getRootPane().getGlassPane(); + if (glassPane != null) { + glassPane.setVisible(true); + // Set wait cursor + glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + } + + // Show popup menu + jpo.show(oxygenFrame, popupLocation.x - oxygenFrame.getLocation().x, popupLocation.y - oxygenFrame.getLocation().y); + + // Add a popup menu listener + jpo.addPopupMenuListener(new PopupMenuListener() { + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + } + + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + // Reset cursor to default + if (glassPane != null) { + glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + glassPane.setVisible(false); + } + } + + public void popupMenuCanceled(PopupMenuEvent e) { + } + }); + + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Insert element at the caret position."; + } + +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/InsertImageOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/InsertImageOperation.java new file mode 100644 index 0000000..81447f8 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/InsertImageOperation.java @@ -0,0 +1,213 @@ +package simple.documentation.framework.operations; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.net.MalformedURLException; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.filechooser.FileFilter; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; + + +/** + * Insert image operation. + */ +public class InsertImageOperation implements AuthorOperation { + + // + // Implementing the Author Operation Interface. + // + + /** + * Performs the operation. + */ + public void doOperation(AuthorAccess authorAccess, + ArgumentsMap arguments) + throws IllegalArgumentException, + AuthorOperationException { + + JFrame oxygenFrame = (JFrame) authorAccess.getWorkspaceAccess().getParentFrame(); + String href = displayURLDialog(oxygenFrame); + if (href.length() != 0) { + // Creates the image XML fragment. + String imageFragment = + ""; + + // Inserts this fragment at the caret position. + int caretPosition = authorAccess.getEditorAccess().getCaretOffset(); + authorAccess.getDocumentController().insertXMLFragment(imageFragment, caretPosition); + } + } + + /** + * Has no arguments. + * + * @return null. + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + + /** + * @return A description of the operation. + */ + public String getDescription() { + return "Inserts an image element. Asks the" + + " user for a URL reference."; + } + + // + // End of interface implementation. + // + + // + // Auxiliary methods. + // + + /** + * Displays the URL dialog. + * + * @param parentFrame The parent frame for + * the dialog. + * @return The selected URL string value, + * or the empty string if the user canceled + * the URL selection. + */ + private String displayURLDialog(JFrame parentFrame) { + + final JDialog dlg = new JDialog(parentFrame, + "Enter the value for the href attribute", true); + JPanel mainContent = new JPanel(new GridBagLayout()); + + // The text field. + GridBagConstraints cstr = new GridBagConstraints(); + cstr.gridx = 0; + cstr.gridy = 0; + cstr.weightx = 0; + cstr.gridwidth = 1; + cstr.fill = GridBagConstraints.HORIZONTAL; + mainContent.add(new JLabel("Image URI:"), cstr); + + cstr.gridx = 1; + cstr.weightx = 1; + final JTextField urlField = new JTextField(); + urlField.setColumns(15); + mainContent.add(urlField, cstr); + + // Add the "Browse button." + cstr.gridx = 2; + cstr.weightx = 0; + JButton browseButton = new JButton("Browse"); + browseButton.addActionListener(new ActionListener() { + + /** + * Shows a file chooser dialog. + */ + public void actionPerformed(ActionEvent e) { + JFileChooser fileChooser = new JFileChooser(); + + fileChooser.setMultiSelectionEnabled(false); + // Accepts only the image files. + fileChooser.setFileFilter(new FileFilter() { + @Override + public String getDescription() { + return "Image files"; + } + + @Override + public boolean accept(File f) { + String fileName = f.getName(); + return f.isFile() && + ( fileName.endsWith(".jpeg") + || fileName.endsWith(".jpg") + || fileName.endsWith(".gif") + || fileName.endsWith(".png") + || fileName.endsWith(".svg")); + } + }); + if (fileChooser.showOpenDialog(dlg) + == JFileChooser.APPROVE_OPTION) { + File file = fileChooser.getSelectedFile(); + try { + // Set the file into the text field. + urlField.setText(file.toURI().toURL().toString()); + } catch (MalformedURLException ex) { + // This should not happen. + ex.printStackTrace(); + } + } + } + }); + mainContent.add(browseButton, cstr); + + // Add the "Ok" button to the layout. + cstr.gridx = 0; + cstr.gridy = 1; + cstr.weightx = 0; + JButton okButton = new JButton("Ok"); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dlg.setVisible(false); + } + }); + mainContent.add(okButton, cstr); + mainContent.setBorder( + BorderFactory.createEmptyBorder(10, 5, 10, 5)); + + // Add the "Cancel" button to the layout. + cstr.gridx = 2; + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + urlField.setText(""); + dlg.setVisible(false); + } + }); + mainContent.add(cancelButton, cstr); + + // When the user closes the dialog + // from the window decoration, + // assume "Cancel" action. + dlg.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + urlField.setText(""); + } + }); + + dlg.getContentPane().add(mainContent); + dlg.pack(); + dlg.setLocationRelativeTo(parentFrame); + dlg.setVisible(true); + return urlField.getText(); + } + + /** + * Test method. + * + * @param args The arguments are ignored. + */ + public static void main(String[] args) { + InsertImageOperation operation = + new InsertImageOperation(); + System.out.println("Choosen URL: " + + operation.displayURLDialog(new JFrame())); + } +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/OpenInNewEditor.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/OpenInNewEditor.java new file mode 100644 index 0000000..8303849 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/OpenInNewEditor.java @@ -0,0 +1,39 @@ +package simple.documentation.framework.operations; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; + +/** + * Open the selected text in a new TXT editor. + */ +public class OpenInNewEditor implements AuthorOperation { + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + public void doOperation(AuthorAccess authorAccess, ArgumentsMap arg1) throws IllegalArgumentException, + AuthorOperationException { + String selectedText = authorAccess.getEditorAccess().getSelectedText(); + // Open in new editor + authorAccess.getWorkspaceAccess().createNewEditor("txt", null, selectedText); + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + // No arguments + return null; + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Open new editor"; + } + +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/QueryDatabaseOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/QueryDatabaseOperation.java new file mode 100644 index 0000000..6a5b4f9 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/QueryDatabaseOperation.java @@ -0,0 +1,196 @@ +package simple.documentation.framework.operations; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Properties; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; + +/** + * Query DB operation. + */ +public class QueryDatabaseOperation implements AuthorOperation{ + private static String ARG_JDBC_DRIVER ="jdbc_driver"; + private static String ARG_USER ="user"; + private static String ARG_PASSWORD ="password"; + private static String ARG_SQL ="sql"; + private static String ARG_CONNECTION ="connection"; + + /** + * @return The array of arguments the developer must specify when + * configuring the action. + */ + public ArgumentDescriptor[] getArguments() { + ArgumentDescriptor args[] = new ArgumentDescriptor[] { + new ArgumentDescriptor( + ARG_JDBC_DRIVER, + ArgumentDescriptor.TYPE_STRING, + "The name of the Java class that is the JDBC driver."), + new ArgumentDescriptor( + ARG_CONNECTION, + ArgumentDescriptor.TYPE_STRING, + "The database URL connection string."), + new ArgumentDescriptor( + ARG_USER, + ArgumentDescriptor.TYPE_STRING, + "The name of the database user."), + new ArgumentDescriptor( + ARG_PASSWORD, + ArgumentDescriptor.TYPE_STRING, + "The database password."), + new ArgumentDescriptor( + ARG_SQL, + ArgumentDescriptor.TYPE_STRING, + "The SQL statement to be executed.") + }; + return args; + } + + /** + * @return The operation description. + */ + public String getDescription() { + return "Executes a database query and puts the result in a table."; + } + + public void doOperation(AuthorAccess authorAccess, ArgumentsMap map) + throws IllegalArgumentException, AuthorOperationException { + // Collects the arguments. + String jdbcDriver = + (String)map.getArgumentValue(ARG_JDBC_DRIVER); + String connection = + (String)map.getArgumentValue(ARG_CONNECTION); + String user = + (String)map.getArgumentValue(ARG_USER); + String password = + (String)map.getArgumentValue(ARG_PASSWORD); + String sql = + (String)map.getArgumentValue(ARG_SQL); + int caretPosition = authorAccess.getEditorAccess().getCaretOffset(); + try { + if (jdbcDriver == null) { + throw new AuthorOperationException("No jdbc driver provided."); + } + if (connection == null) { + throw new AuthorOperationException("No connection provided."); + } + if (user == null) { + throw new AuthorOperationException("No user provided."); + } + if (sql == null) { + throw new AuthorOperationException("No sql provided."); + } + authorAccess.getDocumentController().insertXMLFragment( + getFragment(jdbcDriver, connection, user, password, sql), + caretPosition); + } catch (SQLException e) { + throw new AuthorOperationException( + "The operation failed due to the following database error: " + + e.getMessage(), e); + } catch (ClassNotFoundException e) { + throw new AuthorOperationException( + "The JDBC database driver was not found. Tried to load ' " + + jdbcDriver + "'", e); + } + } + + /** + * Creates a connection to the database, executes + * the SQL statement and creates an XML fragment + * containing a table element that wraps the data + * from the result set. + * + * + * @param jdbcDriver The class name of the JDBC driver. + * @param connectionURL The connection URL. + * @param user The database user. + * @param password The password. + * @param sql The SQL statement. + * @return The string containing the XML fragment. + * + * @throws SQLException thrown when there is a + * problem accessing the database or there are + * erors in the SQL expression. + * @throws ClassNotFoundException when the JDBC + * driver class could not be loaded. + */ + private String getFragment( + String jdbcDriver, + String connectionURL, + String user, + String password, + String sql) throws + SQLException, + ClassNotFoundException { + Properties pr = new Properties(); + pr.put("characterEncoding", "UTF8"); + pr.put("useUnicode", "TRUE"); + pr.put("user", user); + pr.put("password", password); + // Loads the database driver. + Class.forName(jdbcDriver); + // Opens the connection + Connection connection = + DriverManager.getConnection(connectionURL, pr); + java.sql.Statement statement = + connection.createStatement(); + ResultSet resultSet = + statement.executeQuery(sql); + StringBuffer fragmentBuffer = new StringBuffer(); + fragmentBuffer.append( + ""); + // + // Creates the table header. + // + fragmentBuffer.append("
    "); + ResultSetMetaData metaData = resultSet.getMetaData(); + int columnCount = metaData.getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + fragmentBuffer.append("
    "); + } + fragmentBuffer.append(""); + // + // Creates the table content. + // + while (resultSet.next()) { + fragmentBuffer.append(""); + for (int i = 1; i <= columnCount; i++) { + fragmentBuffer.append(""); + } + fragmentBuffer.append(""); + } + fragmentBuffer.append("
    "); + fragmentBuffer.append( + xmlEscape(metaData.getColumnName(i))); + fragmentBuffer.append("
    "); + fragmentBuffer.append( + xmlEscape(resultSet.getObject(i))); + fragmentBuffer.append("
    "); + // Cleanup + resultSet.close(); + statement.close(); + connection.close(); + return fragmentBuffer.toString(); + } + + /** + * Some of the values from the database table + * may contain characters that must be escaped + * in XML, to ensure the fragment is well formed. + * + * @param object The object from the database. + * @return The escaped string representation. + */ + private String xmlEscape(Object object) { + String str = String.valueOf(object); + return str. + replaceAll("&", "&"). + replaceAll("<", "<"); + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFRefreshCSSOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFRefreshCSSOperation.java new file mode 100644 index 0000000..93fc555 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFRefreshCSSOperation.java @@ -0,0 +1,38 @@ +package simple.documentation.framework.operations; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.access.AuthorEditorAccess; + +/** + * Refresh CSS operation. + * + */ +public class SDFRefreshCSSOperation implements AuthorOperation { + + public void doOperation(AuthorAccess authorAccess, ArgumentsMap args) + throws IllegalArgumentException, AuthorOperationException { + AuthorEditorAccess access = authorAccess.getEditorAccess(); + // Reload the CSS files and perform a refresh on the whole document to recompute + // the layout + access.refresh(); + } + + /** + * Arguments. + */ + public ArgumentDescriptor[] getArguments() { + // No arguments + return null; + } + + /** + * Description. + */ + public String getDescription() { + return "Refresh CSS operation for Simple Documentation Framework"; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFShowFileStatusOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFShowFileStatusOperation.java new file mode 100644 index 0000000..585cfca --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFShowFileStatusOperation.java @@ -0,0 +1,45 @@ +package simple.documentation.framework.operations; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; + +/** + * Show file status operation. + * + */ +public class SDFShowFileStatusOperation implements AuthorOperation { + + public void doOperation(AuthorAccess authorAccess, ArgumentsMap args) + throws IllegalArgumentException, AuthorOperationException { + // Build the file status message. + StringBuilder message = new StringBuilder(); + // Editor location + message.append("Location: " + authorAccess.getEditorAccess().getEditorLocation() + "\n"); + // Determine if the document from the editor contains unsaved modifications. + message.append("Modified: " + authorAccess.getEditorAccess().isModified() + "\n"); + // Determine if the document from the editor was ever saved. + message.append("Untitled: " + authorAccess.getEditorAccess().isNewDocument()); + + // Show the informations about the file status + authorAccess.getWorkspaceAccess().showInformationMessage(message.toString()); + } + + /** + * Arguments. + */ + public ArgumentDescriptor[] getArguments() { + // No arguments + return null; + } + + /** + * Description + */ + public String getDescription() { + return "Show the status of the current file"; + } + +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFStrictModeOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFStrictModeOperation.java new file mode 100644 index 0000000..cb73acf --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SDFStrictModeOperation.java @@ -0,0 +1,54 @@ +package simple.documentation.framework.operations; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; + +/** + * + * Strict Mode Operation used to change the permissions to change parts of the document content. + * + */ +public class SDFStrictModeOperation implements AuthorOperation { + + // The strict mode key used to store the strict mode option. + private String strictModeOptionKey = "strictMode"; + + /** + * The Strict mode has changed. + */ + public void doOperation(final AuthorAccess authorAccess, ArgumentsMap args) + throws IllegalArgumentException, AuthorOperationException { + + // Get the strict mode option value from the option storage. + String strictMode = authorAccess.getOptionsStorage().getOption(strictModeOptionKey, "false"); + boolean enabled = Boolean.parseBoolean(strictMode); + + // Change the strict mode option state + enabled = !enabled; + + // Save the new value of the strict mode option + authorAccess.getOptionsStorage().setOption(strictModeOptionKey, String.valueOf(enabled)); + + // Show the strict mode operation status. + String statusMessage = "Strict Mode: " + (enabled ? " ON " : "OFF"); + authorAccess.getWorkspaceAccess().showStatusMessage(statusMessage); + } + + /** + * Arguments. + */ + public ArgumentDescriptor[] getArguments() { + // No arguments + return null; + } + + /** + * Description + */ + public String getDescription() { + return "Strict mode operation"; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SelectNodesInOutlinerOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SelectNodesInOutlinerOperation.java new file mode 100644 index 0000000..defe368 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/SelectNodesInOutlinerOperation.java @@ -0,0 +1,103 @@ +package simple.documentation.framework.operations; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.text.BadLocationException; +import javax.swing.tree.TreePath; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.node.AuthorDocument; +import ro.sync.ecss.extensions.api.node.AuthorElement; +import ro.sync.ecss.extensions.api.node.AuthorNode; +import ro.sync.ecss.extensions.api.structure.AuthorOutlineCustomizer; +import simple.documentation.framework.extensions.SDFAuthorOutlineCustomizer; + +/** + * Select in the Outline the children nodes of the node at caret. + */ +public class SelectNodesInOutlinerOperation implements AuthorOperation { + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + public void doOperation(AuthorAccess authorAccess, ArgumentsMap args) + throws IllegalArgumentException, AuthorOperationException { + // Renderer customizer used to find if a given node is filtered in the Outline. + AuthorOutlineCustomizer rendererCustomizer = new SDFAuthorOutlineCustomizer(); + + int caretOffset = authorAccess.getEditorAccess().getCaretOffset(); + try { + // Node at caret position + AuthorNode currentNode = authorAccess.getDocumentController().getNodeAtOffset(caretOffset); + if (currentNode instanceof AuthorElement) { + AuthorElement currentElement = (AuthorElement)currentNode; + // Find the content nodes + List contentNodes = currentElement.getContentNodes(); + List selectTreePaths = new ArrayList(); + LinkedList reversedPath = findReversedPath(authorAccess, rendererCustomizer, + currentNode); + + for (AuthorNode authorNode : contentNodes) { + if (!rendererCustomizer.ignoreNode(authorNode)) { + LinkedList pathList = new LinkedList(reversedPath); + pathList.add(authorNode); + // Add the children tree path in the selected tree paths list + selectTreePaths.add(new TreePath(pathList.toArray(new AuthorNode[0]))); + } + } + + // Select the children tree paths in the Outline + authorAccess.getOutlineAccess().setSelectionPaths(selectTreePaths.toArray(new TreePath[0])); + } + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Select nodes in the Outliner"; + } + + /** + * Builds the list of node parents up to and including the root node, where the + * original node is the last element in the returned array. + * + * @param authorAccess The author access. + * @param rendererCustomizer Renderer customizer used to find if a given node + * is filtered in the Outline. + * @param node The node to reverse path for. + * @return The path nodes list. + */ + private LinkedList findReversedPath(AuthorAccess authorAccess, + AuthorOutlineCustomizer rendererCustomizer, AuthorNode node) { + AuthorDocument document = authorAccess.getDocumentController().getAuthorDocumentNode(); + + // Builds the path. + LinkedList reversedPath = new LinkedList(); + while (node != null && !rendererCustomizer.ignoreNode(node)) { + reversedPath.addFirst(node); + if (node == document) { + // Just added root. + break; + } + node = node.getParent(); + } + return reversedPath; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/TrasformOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/TrasformOperation.java new file mode 100644 index 0000000..a4d46d6 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/TrasformOperation.java @@ -0,0 +1,82 @@ +package simple.documentation.framework.operations; + +import java.io.File; +import java.io.StringWriter; +import java.net.MalformedURLException; + +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; + +import org.xml.sax.InputSource; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.access.AuthorXMLUtilAccess; + +/** + * Custom transform operation using Saxon EE transformer. + */ +public class TrasformOperation implements AuthorOperation { + + public void doOperation(AuthorAccess authorAccess, ArgumentsMap arguments) + throws IllegalArgumentException, AuthorOperationException { + // Choose the XSLT used in the transform operation + File xsltFile = authorAccess.getWorkspaceAccess().chooseFile( + // Title + "Choose the XSLT", + // Extensions + new String[] {"xsl", "xslt"}, + // Filter description + "XSLT files", + // Open for save + false); + + if (xsltFile != null) { + try { + String xslSystemId = xsltFile.toURI().toURL().toString(); + // Create the XSLT source used in transform operation + Source xslSource = new SAXSource(new InputSource(xslSystemId)); + // Create a XSL transformer without Oxygen options + Transformer xslTransformer = authorAccess.getXMLUtilAccess().createXSLTTransformer(xslSource, null, AuthorXMLUtilAccess.TRANSFORMER_SAXON_ENTERPRISE_EDITION, false); + Source editorSource = new SAXSource(new InputSource(authorAccess.getEditorAccess().createContentReader())); + StringWriter result = new StringWriter(); + // Transform the current document using the specified XSLT + xslTransformer.transform(editorSource, new StreamResult(result)); + StringBuffer resultBuffer = result.getBuffer(); + // Display the result + authorAccess.getWorkspaceAccess().showInformationMessage("Transformation result: " + resultBuffer.toString()); + authorAccess.getWorkspaceAccess().showStatusMessage("Transformation finished"); + } catch (TransformerConfigurationException e) { + // Display the error message + authorAccess.getWorkspaceAccess().showErrorMessage(e.getMessage()); + } catch (TransformerException e) { + // Display the error message + authorAccess.getWorkspaceAccess().showErrorMessage(e.getMessage()); + } catch (MalformedURLException e) { + // Display the error message + authorAccess.getWorkspaceAccess().showErrorMessage(e.getMessage()); + } + } + } + + /** + * Arguments + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + + /** + * Description + */ + public String getDescription() { + return "Custom transform operation using Saxon EE transformer."; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/AddHighlightOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/AddHighlightOperation.java new file mode 100644 index 0000000..f90b68e --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/AddHighlightOperation.java @@ -0,0 +1,71 @@ +package simple.documentation.framework.operations.highlight; + +import java.util.LinkedHashMap; + +import javax.swing.JFrame; +import javax.swing.text.BadLocationException; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlighter; +import ro.sync.ecss.extensions.api.node.AuthorNode; +import ro.sync.ecss.extensions.commons.ui.OKCancelDialog; + +/** + * Operation used to highlight element from the caret position. + */ +public class AddHighlightOperation implements AuthorOperation { + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + public void doOperation(AuthorAccess authorAccess, ArgumentsMap map) throws IllegalArgumentException, + AuthorOperationException { + // Show dialog for adding highlight comment + AuthorPersistentHighlighter highlighter = authorAccess.getEditorAccess().getPersistentHighlighter(); + EditHighlightsDialog commentDlg = new EditHighlightsDialog( + (JFrame) authorAccess.getWorkspaceAccess().getParentFrame(), + "Add highlight comment", + true, + null, + authorAccess); + commentDlg.showDialog(); + if (commentDlg.getResult() == OKCancelDialog.RESULT_OK) { + int caretOffset = authorAccess.getEditorAccess().getCaretOffset(); + try { + // Highlight the node at caret + AuthorNode nodeAtCaret = authorAccess.getDocumentController().getNodeAtOffset(caretOffset); + String authorName = authorAccess.getReviewController().getReviewerAuthorName(); + String timestamp = authorAccess.getReviewController().getCurrentTimestamp(); + + // Compose highlight properties + LinkedHashMap properties = new LinkedHashMap(); + properties.put(HighlightProperties.ID, timestamp); + properties.put(HighlightProperties.AUTHOR, authorName); + properties.put(HighlightProperties.COMMENT, commentDlg.getComment()); + // Add highlight + highlighter.addHighlight(nodeAtCaret.getStartOffset(), nodeAtCaret.getEndOffset(), properties); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Highlight element from the caret position."; + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ChangeReviewAuthorDialog.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ChangeReviewAuthorDialog.java new file mode 100644 index 0000000..0fd043e --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ChangeReviewAuthorDialog.java @@ -0,0 +1,55 @@ +package simple.documentation.framework.operations.highlight; + +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; + +import ro.sync.ecss.extensions.commons.ui.OKCancelDialog; + +/** + * Dialog used for changing the current review author + */ +@SuppressWarnings("serial") +public class ChangeReviewAuthorDialog extends OKCancelDialog { + /** + * Combo box containing all possible author names + */ + private JComboBox authorNamesComboBox; + + /** + * Constructor. + * + * @param parentFrame The parent frame. + * @param title The dialog title. + * @param authorNames All the possible author names. + */ + public ChangeReviewAuthorDialog( + JFrame parentFrame, + String title, + String[] authorNames) { + super(parentFrame, title, true); + // Add label + add(new JLabel("Choose Review Author: ")); + // Add the combobox containing possible author names + authorNamesComboBox = new JComboBox(authorNames); + add(authorNamesComboBox); + } + + /** + * Show the dialog. + */ + public void showDialog() { + setLocationRelativeTo(null); + pack(); + setVisible(true); + } + + /** + * Get the selected author name. + * + * @return The selected author name. + */ + public String getSelectedAuthorName() { + return (String) authorNamesComboBox.getSelectedItem(); + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ChangeReviewAuthorOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ChangeReviewAuthorOperation.java new file mode 100644 index 0000000..47f5dff --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ChangeReviewAuthorOperation.java @@ -0,0 +1,51 @@ +package simple.documentation.framework.operations.highlight; + +import javax.swing.JFrame; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.commons.ui.OKCancelDialog; + +/** + * Operation that allow changing the author. + */ +public class ChangeReviewAuthorOperation implements AuthorOperation { + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + public void doOperation(AuthorAccess authorAccess, ArgumentsMap args) + throws IllegalArgumentException, AuthorOperationException { + ChangeReviewAuthorDialog commentDlg = new ChangeReviewAuthorDialog( + (JFrame) authorAccess.getWorkspaceAccess().getParentFrame(), + "Change Review Author", + new String[] {"Author_1", "Author_2", "Author_3", "Default"}); + // Show the dialog + commentDlg.showDialog(); + if (commentDlg.getResult() == OKCancelDialog.RESULT_OK) { + String reviewerAuthorName = commentDlg.getSelectedAuthorName(); + // If the the reviewer author name is set to null, the default author name is used. + reviewerAuthorName = "Default".equals(reviewerAuthorName) ? null : reviewerAuthorName; + // Set the reviewer author name + authorAccess.getReviewController().setReviewerAuthorName(reviewerAuthorName); + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Change review author name"; + } + +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/EditHighlightsDialog.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/EditHighlightsDialog.java new file mode 100644 index 0000000..1d23766 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/EditHighlightsDialog.java @@ -0,0 +1,190 @@ +package simple.documentation.framework.operations.highlight; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.border.BevelBorder; + +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight; +import ro.sync.ecss.extensions.commons.ui.OKCancelDialog; + +/** + * Dialog used for adding or editing highlights. + */ +@SuppressWarnings("serial") +public class EditHighlightsDialog extends OKCancelDialog { + /** + * Information label (presents highlight ID and author). + */ + private JLabel infoLabel; + /** + * Comment area. + */ + private JTextArea commentArea; + /** + * Map between highlight and edited properties. + */ + private Map> mapHighlightsToProps; + /** + * Current edited highlight index. + */ + private final int[] currentIndex = new int[1]; + /** + * Current edited highlight. + */ + private AuthorPersistentHighlight currentHighlight; + /** + * The Author access. + */ + private final AuthorAccess authorAccess; + + /** + * Constructor. + * + * @param parentFrame The parent frame. + * @param title The dialog title. + * @param modal 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 highlights, + final AuthorAccess auhorAccess) { + super(parentFrame, title, modal); + this.authorAccess = auhorAccess; + + boolean editHighlights = highlights != null && highlights.size() > 0; + + commentArea = new JTextArea(); + commentArea.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); + + // Add scroll pane + JScrollPane commentAreaPane = new JScrollPane(commentArea); + commentAreaPane.setPreferredSize(new Dimension(400, 200)); + commentArea.setMargin(new Insets(10, 10, 10 , 10)); + // Add comment area + add(commentAreaPane, BorderLayout.CENTER); + + if (editHighlights) { + mapHighlightsToProps = new LinkedHashMap>(); + currentHighlight = highlights.get(0); + JPanel northPanel = new JPanel(); + infoLabel = new JLabel(); + northPanel.add(infoLabel); + // Add next button if necessary + if (highlights.size() > 1) { + final JButton nextButton = new JButton("Next"); + nextButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveCurrentHighlightProps(currentHighlight); + + currentIndex[0] = currentIndex[0] + 1; + currentHighlight = highlights.get(currentIndex[0]); + + // Display next highlight + displayHighlightProps(currentHighlight); + + // Disable next button if necessary + if (highlights.size() == currentIndex[0] + 1) { + nextButton.setEnabled(false); + } + } + }); + // Add next button + northPanel.add(nextButton); + } + add(northPanel, BorderLayout.NORTH); + + // Display properties for the current highlight + displayHighlightProps(currentHighlight); + } + } + + private void saveCurrentHighlightProps(AuthorPersistentHighlight highlight) { + // Save edited properties for the current map + LinkedHashMap props = highlight.getClonedProperties(); + props.put(HighlightProperties.COMMENT, commentArea.getText()); + mapHighlightsToProps.put(highlight, props); + } + + /** + * @see ro.sync.ecss.extensions.commons.ui.OKCancelDialog#doOK() + */ + @Override + protected void doOK() { + if (currentHighlight != null) { + saveCurrentHighlightProps(currentHighlight); + if (mapHighlightsToProps != null) { + Set highlights = mapHighlightsToProps.keySet(); + for (AuthorPersistentHighlight highlight : highlights) { + // Update the timestamp + mapHighlightsToProps.get(highlight).put(HighlightProperties.ID, authorAccess.getReviewController().getCurrentTimestamp()); + } + } + } + super.doOK(); + } + + /** + * Display highlight properties. + * + * @param highlight The current highlight. + */ + private void displayHighlightProps(AuthorPersistentHighlight highlight) { + LinkedHashMap cloneProperties = highlight.getClonedProperties(); + + // Highlight properties + String id = cloneProperties.get(HighlightProperties.ID); + String author = cloneProperties.get(HighlightProperties.AUTHOR); + String comment = cloneProperties.get(HighlightProperties.COMMENT); + + // Display highlight comment + commentArea.setText(comment); + + // Display highlight ID and author + infoLabel.setText("Id: " + id + " Author: " + author); + } + + /** + * Show the dialog. + */ + public void showDialog() { + setLocationRelativeTo(null); + pack(); + setVisible(true); + } + + /** + * Get the last edited comment. + * + * @return The inserted comment. + */ + public String getComment() { + return commentArea.getText(); + } + + /** + * @return Returns the highlights to properties map. + */ + public Map> getMapHighlightsToProps() { + return mapHighlightsToProps; + } +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/EditHighlightsOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/EditHighlightsOperation.java new file mode 100644 index 0000000..d144e97 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/EditHighlightsOperation.java @@ -0,0 +1,79 @@ +package simple.documentation.framework.operations.highlight; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.swing.JFrame; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlight; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlighter; +import ro.sync.ecss.extensions.commons.ui.OKCancelDialog; + +/** + * Operation used to edit the highlights from the caret position. + */ +public class EditHighlightsOperation implements AuthorOperation { + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + public void doOperation(AuthorAccess authorAccess, ArgumentsMap args) + throws IllegalArgumentException, AuthorOperationException { + AuthorPersistentHighlighter highlighter = authorAccess.getEditorAccess().getPersistentHighlighter(); + AuthorPersistentHighlight[] highlights = highlighter.getHighlights(); + if (highlights.length > 0) { + int caretOffset = authorAccess.getEditorAccess().getCaretOffset(); + List caretHighlights = new ArrayList(); + // Remove highlights from the caret position + for (AuthorPersistentHighlight highlight : highlights) { + // Get the highlights from the caret position + if (highlight.getStartOffset() <= caretOffset && highlight.getEndOffset() >= caretOffset) { + caretHighlights.add(highlight); + } + } + + if (caretHighlights.size() > 0) { + // Show edit highlights dialog + EditHighlightsDialog commentDlg = new EditHighlightsDialog( + (JFrame) authorAccess.getWorkspaceAccess().getParentFrame(), + "Add highlight comment", + true, + caretHighlights, + authorAccess); + commentDlg.showDialog(); + // Save edited highlights if dialog result is OK + if (commentDlg.getResult() == OKCancelDialog.RESULT_OK) { + Map> mapHighlightsToProps = commentDlg.getMapHighlightsToProps(); + Set highlightsSet = mapHighlightsToProps.keySet(); + for (AuthorPersistentHighlight h : highlightsSet) { + // Save edited properties + highlighter.setProperties(h, mapHighlightsToProps.get(h)); + } + } + } + } + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Edit Highlights from the caret position"; + } + +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/HighlightProperties.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/HighlightProperties.java new file mode 100644 index 0000000..2f0c1be --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/HighlightProperties.java @@ -0,0 +1,19 @@ +package simple.documentation.framework.operations.highlight; + +/** + * Hightlight properties names + */ +public interface HighlightProperties { + /** + * Highlight author. + */ + static final String AUTHOR = "author"; + /** + * Highlight ID. + */ + static final String ID = "id"; + /** + * Highlight comment. + */ + static final String COMMENT = "comment"; +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/RemoveAllHighlightsOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/RemoveAllHighlightsOperation.java new file mode 100644 index 0000000..f61b2dd --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/RemoveAllHighlightsOperation.java @@ -0,0 +1,41 @@ +package simple.documentation.framework.operations.highlight; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlighter; + +/** + * Operation used to remove all persistent highlights. + */ +public class RemoveAllHighlightsOperation implements AuthorOperation { + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + public void doOperation(AuthorAccess authorAccess, ArgumentsMap args) + throws IllegalArgumentException, AuthorOperationException { + AuthorPersistentHighlighter highlighter = authorAccess.getEditorAccess().getPersistentHighlighter(); + int highlights = highlighter.getHighlights().length; + // Remove all highlights + highlighter.removeAllHighlights(); + authorAccess.getWorkspaceAccess().showInformationMessage(highlights == 1 ? "1 highlight removed" : highlights + " highlights removed"); + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Remove all persistent highlights"; + } + +} diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ReviewParaOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ReviewParaOperation.java new file mode 100644 index 0000000..a4fca42 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/highlight/ReviewParaOperation.java @@ -0,0 +1,108 @@ +package simple.documentation.framework.operations.highlight; + +import java.awt.Component; +import java.util.LinkedHashMap; + +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.text.BadLocationException; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.ecss.extensions.api.highlights.AuthorHighlighter; +import ro.sync.ecss.extensions.api.highlights.AuthorPersistentHighlighter; +import ro.sync.ecss.extensions.api.highlights.ColorHighlightPainter; +import ro.sync.ecss.extensions.api.node.AuthorNode; +import ro.sync.ecss.extensions.commons.ui.OKCancelDialog; +import ro.sync.exml.view.graphics.Color; + + +/** + * Operation used to highlight a paragraph as reviewed. + */ +public class ReviewParaOperation implements AuthorOperation { + /** + * Highlight author. + */ + static final String AUTHOR = "author"; + /** + * Highlight ID. + */ + static final String ID = "id"; + /** + * Highlight comment. + */ + static final String COMMENT = "comment"; + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + public void doOperation(AuthorAccess authorAccess, ArgumentsMap map) throws IllegalArgumentException, + AuthorOperationException { + // Highlight the selected paragraph if any. + AuthorNode selectedNode = authorAccess.getEditorAccess().getFullySelectedNode(); + if (selectedNode != null) { + // Show dialog for adding highlight comment + AuthorPersistentHighlighter persistentHighlighter = authorAccess.getEditorAccess().getPersistentHighlighter(); + AuthorHighlighter highlighter = authorAccess.getEditorAccess().getHighlighter(); + EditHighlightsDialog commentDlg = new EditHighlightsDialog( + (JFrame) authorAccess.getWorkspaceAccess().getParentFrame(), + "Review Paragraph", + true, + null, + authorAccess); + commentDlg.showDialog(); + if (commentDlg.getResult() == OKCancelDialog.RESULT_OK) { + + // Get author name and timestamp. + String authorName = authorAccess.getReviewController().getReviewerAuthorName(); + String timestamp = authorAccess.getReviewController().getCurrentTimestamp(); + + // Compose highlight properties + LinkedHashMap properties = new LinkedHashMap(); + properties.put(ID, timestamp); + properties.put(AUTHOR, authorName); + String comment = commentDlg.getComment(); + properties.put(COMMENT, comment); + int startOffset = selectedNode.getStartOffset(); + int endOffset = selectedNode.getEndOffset(); + if (comment != null && comment.trim().length() > 0) { + // Add a persistent highlight + persistentHighlighter.addHighlight(startOffset, endOffset, properties); + } else { + // Add non-persistent highlight + + ColorHighlightPainter painter = new ColorHighlightPainter(); + painter.setTextForegroundColor(Color.COLOR_RED_DARKER); + + try { + highlighter.addHighlight(startOffset, endOffset, painter, null); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + } + } else { + JOptionPane.showMessageDialog( + (Component) authorAccess.getWorkspaceAccess().getParentFrame(), + "Select the whole paragraph!!!"); + } + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Review selected paragraph."; + } + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + return null; + } +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/table/InsertTableOperation.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/table/InsertTableOperation.java new file mode 100644 index 0000000..11c7db6 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/table/InsertTableOperation.java @@ -0,0 +1,89 @@ +package simple.documentation.framework.operations.table; + +import java.awt.Component; + +import javax.swing.JFrame; + +import ro.sync.ecss.extensions.api.ArgumentDescriptor; +import ro.sync.ecss.extensions.api.ArgumentsMap; +import ro.sync.ecss.extensions.api.AuthorAccess; +import ro.sync.ecss.extensions.api.AuthorOperation; +import ro.sync.ecss.extensions.api.AuthorOperationException; +import ro.sync.exml.workspace.api.Platform; +import simple.documentation.framework.operations.table.TableCustomizerDialog.TableInfo; + +/** + * Operation used to insert a SDF table. + */ +public class InsertTableOperation implements AuthorOperation { + + /** + * @see ro.sync.ecss.extensions.api.AuthorOperation#doOperation(ro.sync.ecss.extensions.api.AuthorAccess, ro.sync.ecss.extensions.api.ArgumentsMap) + */ + public void doOperation(AuthorAccess authorAccess, ArgumentsMap args) + throws IllegalArgumentException, AuthorOperationException { + // Show the 'Insert table' dialog + TableInfo tableInfo = null; + if(authorAccess.getWorkspaceAccess().getPlatform() == Platform.STANDALONE) { + TableCustomizerDialog tableCustomizerDialog = new TableCustomizerDialog( + (JFrame) authorAccess.getWorkspaceAccess().getParentFrame()); + tableCustomizerDialog.setLocationRelativeTo( + (Component) authorAccess.getWorkspaceAccess().getParentFrame()); + tableInfo = tableCustomizerDialog.showDialog(); + } + + if (tableInfo != null) { + // Create the table XML fragment + StringBuffer tableXMLFragment = new StringBuffer(); + tableXMLFragment.append(""); + if(tableInfo.getTitle() != null && tableInfo.getTitle().trim().length() > 0) { + tableXMLFragment.append("" + tableInfo.getTitle().trim() + ""); + } + + // Add table body + int columns = tableInfo.getColumnsNumber(); + int rows = tableInfo.getRowsNumber(); + for (int i = 0; i < rows; i++) { + tableXMLFragment.append(""); + for (int j = 0; j < columns; j++) { + tableXMLFragment.append(""); + } + tableXMLFragment.append(""); + } + + tableXMLFragment.append("
    "); + + + // Insert the table + authorAccess.getDocumentController().insertXMLFragmentSchemaAware( + tableXMLFragment.toString(), + authorAccess.getEditorAccess().getCaretOffset()); + } else { + // User canceled the operation + } + } + + /** + * No arguments. The operation will display a dialog for choosing the table attributes. + * + * @see ro.sync.ecss.extensions.api.AuthorOperation#getArguments() + */ + public ArgumentDescriptor[] getArguments() { + return null; + } + + /** + * @see ro.sync.ecss.extensions.api.Extension#getDescription() + */ + public String getDescription() { + return "Insert a SDF table"; + } +} \ No newline at end of file diff --git a/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/table/TableCustomizerDialog.java b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/table/TableCustomizerDialog.java new file mode 100644 index 0000000..f6acad7 --- /dev/null +++ b/oxygen/js-debugger-importer/src-java/simple/documentation/framework/operations/table/TableCustomizerDialog.java @@ -0,0 +1,339 @@ +package simple.documentation.framework.operations.table; + + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JColorChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; + +import ro.sync.ecss.extensions.commons.table.operations.TableCustomizerConstants; +import ro.sync.ecss.extensions.commons.ui.OKCancelDialog; + +/** + * Dialog used to customize the insertion of a table (number of rows, columns, table caption). + * It is used on Standalone implementation. + */ +@SuppressWarnings("serial") +public class TableCustomizerDialog extends OKCancelDialog implements TableCustomizerConstants { + + /** + * If selected the user can specify the table title. + */ + private JCheckBox titleCheckbox; + + /** + * Text field for specify the table title. + */ + private JTextField titleTextField; + + /** + * Used to specify the number of rows. + */ + private JSpinner rowsSpinner; + + /** + * Used to specify the number of columns. + */ + private JSpinner columnsSpinner; + + /** + * If selected the user can specify the table background color. + */ + private JCheckBox tableBgColorCheckbox; + + /** + * Button used to choose table background color. + */ + private JButton tableBgColorButton; + + /** + * Constructor. + * + * @param parentFrame The parent {@link JFrame} of the dialog. + */ + public TableCustomizerDialog( + JFrame parentFrame) { + super(parentFrame, "Insert Table", true); + + // The main panel + JPanel mainPanel = new JPanel(new GridBagLayout()); + mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + GridBagConstraints gridBagConstr = new GridBagConstraints(); + gridBagConstr.anchor = GridBagConstraints.WEST; + gridBagConstr.gridy = 0; + gridBagConstr.gridx = 0; + gridBagConstr.weightx = 0; + gridBagConstr.gridwidth = 1; + gridBagConstr.insets = new Insets(5, 0, 5, 5); + gridBagConstr.fill = GridBagConstraints.NONE; + + // Title check box + titleCheckbox = new JCheckBox("Title"); + titleCheckbox.setName("Title checkbox"); + titleCheckbox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + titleTextField.setEditable(titleCheckbox.isSelected()); + } + }); + titleCheckbox.setBorder(BorderFactory.createEmptyBorder()); + mainPanel.add(titleCheckbox, gridBagConstr); + + // Title text field + titleTextField = new JTextField(); + titleTextField.setName("Title text field"); + gridBagConstr.gridx ++; + gridBagConstr.weightx = 1; + gridBagConstr.fill = GridBagConstraints.HORIZONTAL; + gridBagConstr.insets = new Insets(5, 0, 5, 0); + mainPanel.add(titleTextField, gridBagConstr); + + gridBagConstr.gridy ++; + gridBagConstr.gridx = 0; + gridBagConstr.weightx = 0; + gridBagConstr.gridwidth = 1; + gridBagConstr.insets = new Insets(5, 0, 5, 5); + gridBagConstr.fill = GridBagConstraints.BOTH; + + // Table bgcolor box + tableBgColorCheckbox = new JCheckBox("Table Background"); + tableBgColorButton = new JButton(); + tableBgColorCheckbox.setName("Table Background"); + tableBgColorCheckbox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + tableBgColorButton.setEnabled(tableBgColorCheckbox.isSelected()); + } + }); + tableBgColorCheckbox.setBorder(BorderFactory.createEmptyBorder()); + mainPanel.add(tableBgColorCheckbox, gridBagConstr); + + // Table bg color + tableBgColorButton.setIcon(new Icon() { + public void paintIcon(Component parent, Graphics g, int x, int y) { + Color color = tableBgColorButton.getBackground(); + if (color == null) { + return; + } + Color used4Draw = color; + if (parent != null && !parent.isEnabled()) { + used4Draw = parent.getBackground(); + } + g.setColor(used4Draw); + g.fillRect(x, y, getIconWidth(), getIconHeight()); + g.setColor(used4Draw.darker()); + g.drawRect(x, y, getIconWidth() - 1, getIconHeight() - 1); + } + + public int getIconWidth() { + return tableBgColorButton.getWidth(); + } + + public int getIconHeight() { + return tableBgColorButton.getHeight(); + } + }); + + tableBgColorButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + Color initialBackground = tableBgColorButton.getBackground(); + Color background = JColorChooser.showDialog(null, + "Choose Color", initialBackground); + if (background != null) { + tableBgColorButton.setBackground(background); + + tableBgColorButton.setContentAreaFilled(true); + } + } + }); + tableBgColorButton.setPreferredSize(new Dimension(100, 15)); + gridBagConstr.gridx ++; + gridBagConstr.weightx = 1; + gridBagConstr.fill = GridBagConstraints.HORIZONTAL; + gridBagConstr.insets = new Insets(2, 2, 2, 2); + mainPanel.add(tableBgColorButton, gridBagConstr); + + // Table size panel + JPanel sizePanel = new JPanel(new GridBagLayout()); + sizePanel.setBorder(BorderFactory.createTitledBorder("Table Size")); + + gridBagConstr.gridy ++; + gridBagConstr.gridx = 0; + gridBagConstr.weightx = 1; + gridBagConstr.fill = GridBagConstraints.HORIZONTAL; + gridBagConstr.gridwidth = 2; + gridBagConstr.insets = new Insets(5, 0, 5, 0); + mainPanel.add(sizePanel, gridBagConstr); + + // 'Rows' label + JLabel rowsLabel = new JLabel("Rows"); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 0; + c.insets = new Insets(0, 5, 5, 5); + sizePanel.add(rowsLabel, c); + + // Number of rows text field + rowsSpinner = new JSpinner(); + rowsSpinner.setName("Rows spinner"); + rowsSpinner.setModel(new SpinnerNumberModel(2, 0, 100, 1)); + c.gridx++; + c.weightx = 1; + sizePanel.add(rowsSpinner, c); + + // 'Columns' label + JLabel columnsLabel = new JLabel("Columns"); + c.gridx++; + c.weightx = 0; + sizePanel.add(columnsLabel, c); + + // Number of rows text field + columnsSpinner = new JSpinner(); + columnsSpinner.setName("Columns spinner"); + columnsSpinner.setModel(new SpinnerNumberModel(2, 0, 100, 1)); + c.gridx++; + c.weightx = 1; + sizePanel.add(columnsSpinner, c); + + //Add the main panel + getContentPane().add(mainPanel, BorderLayout.CENTER); + + pack(); + setResizable(false); + } + + /** + * Contains informations about the table element. + */ + class TableInfo { + /** + * Table title. + */ + private final String title; + /** + * Table rows number. + */ + private final int rowsNumber; + /** + * Table columns number. + */ + private final int columnsNumber; + /** + * Table background color. + */ + private final Color tableBgColor; + + /** + * @param title Table title. + * @param rowsNumber Table rows number. + * @param columnsNumber Table columns number. + * @param tableBgColor Table background color. + */ + public TableInfo(String title, int rowsNumber, int columnsNumber, Color tableBgColor) { + this.title = title; + this.rowsNumber = rowsNumber; + this.columnsNumber = columnsNumber; + this.tableBgColor = tableBgColor; + } + + /** + * @return Returns the title. + */ + public String getTitle() { + return title; + } + + /** + * @return Returns the rows number. + */ + public int getRowsNumber() { + return rowsNumber; + } + + /** + * @return Returns the columns number. + */ + public int getColumnsNumber() { + return columnsNumber; + } + + /** + * @return Returns the table background color. + */ + public Color getTableBackgroundColor() { + return tableBgColor; + } + } + + /** + * Show the dialog to customize the table attributes. + * + * @return The object containing informations about the table to be inserted. + * If 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 @@ + +
    + +
    + + + +
    +
    \ No newline at end of file diff --git a/oxygen/js-debugger-importer/templates/book.xml b/oxygen/js-debugger-importer/templates/book.xml new file mode 100644 index 0000000..7586442 --- /dev/null +++ b/oxygen/js-debugger-importer/templates/book.xml @@ -0,0 +1,22 @@ + + + Book Template Title +
    + Section Title + + This content is copyrighted: + + Table Title +
    +
    + + + + +
    CompanyDate
    + +
    +
    +
    diff --git a/oxygen/js-debugger-importer/test.js b/oxygen/js-debugger-importer/test.js new file mode 100644 index 0000000..007a76e --- /dev/null +++ b/oxygen/js-debugger-importer/test.js @@ -0,0 +1,34 @@ +/* + * Unexpected things happen here... + */ + +function a() {} + +b = function() {} + +// Notice the weird behavior : + +typeof a; // object +typeof b; // function + +aclass = function () { + this.setFoo(1); + return this; +} + +typeof aclass; + +aclass.prototype.setFoo = function (v) { + this.foo = v; +} + +anObject = new aclass() ; + +anObject.setFoo(2); + +anObject.foo; + +// Also worth mentionning, you ***must*** use new and this doesn't work : +// +// anobject = aclass(); + diff --git a/oxygen/js-debugger-importer/xsl/sdf.xsl b/oxygen/js-debugger-importer/xsl/sdf.xsl new file mode 100644 index 0000000..3038bd9 --- /dev/null +++ b/oxygen/js-debugger-importer/xsl/sdf.xsl @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + +

    + +

    +
    + +

    + + + +

    +
    + +

    + +

    +
    + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + +