From cb1000d6ee9cb1f46920755189fc839cc2fed275 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 15 Sep 2021 05:16:52 +0200 Subject: [PATCH 01/38] Updating HTML/Java API to most recent version 1.7.2 --- platform/net.java.html.boot.fx/external/binaries-list | 2 +- ...-1.7-license.txt => net.java.html.boot.fx-1.7.2-license.txt} | 2 +- platform/net.java.html.boot.fx/nbproject/project.properties | 2 +- platform/net.java.html.boot.fx/nbproject/project.xml | 2 +- platform/net.java.html.boot.script/external/binaries-list | 2 +- ...-license.txt => net.java.html.boot.script-1.7.2-license.txt} | 2 +- platform/net.java.html.boot.script/nbproject/project.properties | 2 +- platform/net.java.html.boot.script/nbproject/project.xml | 2 +- platform/net.java.html.boot/external/binaries-list | 2 +- ...oot-1.7-license.txt => net.java.html.boot-1.7.2-license.txt} | 2 +- platform/net.java.html.boot/nbproject/project.properties | 2 +- platform/net.java.html.boot/nbproject/project.xml | 2 +- platform/net.java.html.geo/external/binaries-list | 2 +- ....geo-1.7-license.txt => net.java.html.geo-1.7.2-license.txt} | 2 +- platform/net.java.html.geo/nbproject/project.properties | 2 +- platform/net.java.html.geo/nbproject/project.xml | 2 +- platform/net.java.html.json/external/binaries-list | 2 +- ...son-1.7-license.txt => net.java.html.json-1.7.2-license.txt} | 2 +- platform/net.java.html.json/nbproject/project.properties | 2 +- platform/net.java.html.json/nbproject/project.xml | 2 +- platform/net.java.html.sound/external/binaries-list | 2 +- ...nd-1.7-license.txt => net.java.html.sound-1.7.2-license.txt} | 2 +- platform/net.java.html.sound/nbproject/project.properties | 2 +- platform/net.java.html.sound/nbproject/project.xml | 2 +- platform/net.java.html/external/binaries-list | 2 +- ...ava.html-1.7-license.txt => net.java.html-1.7.2-license.txt} | 2 +- platform/net.java.html/nbproject/project.properties | 2 +- platform/net.java.html/nbproject/project.xml | 2 +- platform/o.n.html.ko4j/external/binaries-list | 2 +- .../external/{ko4j-1.7-license.txt => ko4j-1.7.2-license.txt} | 2 +- platform/o.n.html.ko4j/nbproject/project.properties | 2 +- platform/o.n.html.ko4j/nbproject/project.xml | 2 +- platform/o.n.html.xhr4j/external/binaries-list | 2 +- .../external/{xhr4j-1.7-license.txt => xhr4j-1.7.2-license.txt} | 2 +- platform/o.n.html.xhr4j/nbproject/project.properties | 2 +- platform/o.n.html.xhr4j/nbproject/project.xml | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) rename platform/net.java.html.boot.fx/external/{net.java.html.boot.fx-1.7-license.txt => net.java.html.boot.fx-1.7.2-license.txt} (99%) rename platform/net.java.html.boot.script/external/{net.java.html.boot.script-1.7-license.txt => net.java.html.boot.script-1.7.2-license.txt} (99%) rename platform/net.java.html.boot/external/{net.java.html.boot-1.7-license.txt => net.java.html.boot-1.7.2-license.txt} (99%) rename platform/net.java.html.geo/external/{net.java.html.geo-1.7-license.txt => net.java.html.geo-1.7.2-license.txt} (99%) rename platform/net.java.html.json/external/{net.java.html.json-1.7-license.txt => net.java.html.json-1.7.2-license.txt} (99%) rename platform/net.java.html.sound/external/{net.java.html.sound-1.7-license.txt => net.java.html.sound-1.7.2-license.txt} (99%) rename platform/net.java.html/external/{net.java.html-1.7-license.txt => net.java.html-1.7.2-license.txt} (99%) rename platform/o.n.html.ko4j/external/{ko4j-1.7-license.txt => ko4j-1.7.2-license.txt} (99%) rename platform/o.n.html.xhr4j/external/{xhr4j-1.7-license.txt => xhr4j-1.7.2-license.txt} (99%) diff --git a/platform/net.java.html.boot.fx/external/binaries-list b/platform/net.java.html.boot.fx/external/binaries-list index 8be7c481cc51..ad28b379a0e1 100644 --- a/platform/net.java.html.boot.fx/external/binaries-list +++ b/platform/net.java.html.boot.fx/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -F56B997D397F2984442342DD89069F0E086DE8A8 org.netbeans.html:net.java.html.boot.fx:1.7 +C6C7E7F406BCC131A79BD6A1C2B32F47F6E881B9 org.netbeans.html:net.java.html.boot.fx:1.7.2 diff --git a/platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7-license.txt b/platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7.2-license.txt similarity index 99% rename from platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7-license.txt rename to platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7.2-license.txt index 9266dfcdbed9..dc8df7ecf551 100644 --- a/platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7-license.txt +++ b/platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7.2-license.txt @@ -1,5 +1,5 @@ Name: Html4J -Version: 1.7 +Version: 1.7.2 Description: Html4j Boot FX License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.boot.fx/nbproject/project.properties b/platform/net.java.html.boot.fx/nbproject/project.properties index 5974dec2a743..85e71724b9f7 100644 --- a/platform/net.java.html.boot.fx/nbproject/project.properties +++ b/platform/net.java.html.boot.fx/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.boot.fx-1.7.jar=modules/net-java-html-boot-fx.jar +release.external/net.java.html.boot.fx-1.7.2.jar=modules/net-java-html-boot-fx.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.boot.fx/nbproject/project.xml b/platform/net.java.html.boot.fx/nbproject/project.xml index 2e73f4caaadc..92d341e9883d 100644 --- a/platform/net.java.html.boot.fx/nbproject/project.xml +++ b/platform/net.java.html.boot.fx/nbproject/project.xml @@ -28,7 +28,7 @@ net-java-html-boot-fx.jar - external/net.java.html.boot.fx-1.7.jar + external/net.java.html.boot.fx-1.7.2.jar diff --git a/platform/net.java.html.boot.script/external/binaries-list b/platform/net.java.html.boot.script/external/binaries-list index 0f5595da50ca..e87454cfbe5e 100644 --- a/platform/net.java.html.boot.script/external/binaries-list +++ b/platform/net.java.html.boot.script/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -0E0A5295FC07E685E30E60EDE5AB3D1C5D7DA574 org.netbeans.html:net.java.html.boot.script:1.7 +620D43EF251C93A69AA2142A25CFF80351EDDF3B org.netbeans.html:net.java.html.boot.script:1.7.2 diff --git a/platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7-license.txt b/platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7.2-license.txt similarity index 99% rename from platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7-license.txt rename to platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7.2-license.txt index 3e772c092e2e..9abf0bb5b184 100644 --- a/platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7-license.txt +++ b/platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7.2-license.txt @@ -1,5 +1,5 @@ Name: Html4J -Version: 1.7 +Version: 1.7.2 Description: Html4j Boot Script License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.boot.script/nbproject/project.properties b/platform/net.java.html.boot.script/nbproject/project.properties index 9480b8d495ab..6e301da6150d 100644 --- a/platform/net.java.html.boot.script/nbproject/project.properties +++ b/platform/net.java.html.boot.script/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.boot.script-1.7.jar=modules/net-java-html-boot-script.jar +release.external/net.java.html.boot.script-1.7.2.jar=modules/net-java-html-boot-script.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.boot.script/nbproject/project.xml b/platform/net.java.html.boot.script/nbproject/project.xml index 6cbfcf5e9006..d227dfc45ff9 100644 --- a/platform/net.java.html.boot.script/nbproject/project.xml +++ b/platform/net.java.html.boot.script/nbproject/project.xml @@ -28,7 +28,7 @@ net-java-html-boot-script.jar - external/net.java.html.boot.script-1.7.jar + external/net.java.html.boot.script-1.7.2.jar diff --git a/platform/net.java.html.boot/external/binaries-list b/platform/net.java.html.boot/external/binaries-list index ab24e8a0d1d7..62b7981672ab 100644 --- a/platform/net.java.html.boot/external/binaries-list +++ b/platform/net.java.html.boot/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -0D4DBFEA65DCC33F22C13B6469329A5001B1D80D org.netbeans.html:net.java.html.boot:1.7 +97032FDEFB37E38D4483A08EE1C8908DAB628467 org.netbeans.html:net.java.html.boot:1.7.2 diff --git a/platform/net.java.html.boot/external/net.java.html.boot-1.7-license.txt b/platform/net.java.html.boot/external/net.java.html.boot-1.7.2-license.txt similarity index 99% rename from platform/net.java.html.boot/external/net.java.html.boot-1.7-license.txt rename to platform/net.java.html.boot/external/net.java.html.boot-1.7.2-license.txt index ef425f93191e..9ad527cffcc3 100644 --- a/platform/net.java.html.boot/external/net.java.html.boot-1.7-license.txt +++ b/platform/net.java.html.boot/external/net.java.html.boot-1.7.2-license.txt @@ -1,5 +1,5 @@ Name: Html4J -Version: 1.7 +Version: 1.7.2 Description: Html4j Boot License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.boot/nbproject/project.properties b/platform/net.java.html.boot/nbproject/project.properties index 29948b11f481..798d7dab7451 100644 --- a/platform/net.java.html.boot/nbproject/project.properties +++ b/platform/net.java.html.boot/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.boot-1.7.jar=modules/net-java-html-boot.jar +release.external/net.java.html.boot-1.7.2.jar=modules/net-java-html-boot.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.boot/nbproject/project.xml b/platform/net.java.html.boot/nbproject/project.xml index 6d52792f1af3..4efb265675bc 100644 --- a/platform/net.java.html.boot/nbproject/project.xml +++ b/platform/net.java.html.boot/nbproject/project.xml @@ -28,7 +28,7 @@ net-java-html-boot.jar - external/net.java.html.boot-1.7.jar + external/net.java.html.boot-1.7.2.jar diff --git a/platform/net.java.html.geo/external/binaries-list b/platform/net.java.html.geo/external/binaries-list index 5f138b7810ec..e3135fbe9ed2 100644 --- a/platform/net.java.html.geo/external/binaries-list +++ b/platform/net.java.html.geo/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -79D84786D3C3001415C195AE17900A1B5273E6FC org.netbeans.html:net.java.html.geo:1.7 +536E44A4FA6E1AF1B92795C5B7EDFB68A3680427 org.netbeans.html:net.java.html.geo:1.7.2 diff --git a/platform/net.java.html.geo/external/net.java.html.geo-1.7-license.txt b/platform/net.java.html.geo/external/net.java.html.geo-1.7.2-license.txt similarity index 99% rename from platform/net.java.html.geo/external/net.java.html.geo-1.7-license.txt rename to platform/net.java.html.geo/external/net.java.html.geo-1.7.2-license.txt index 65c39b4434c6..79f23f8cc074 100644 --- a/platform/net.java.html.geo/external/net.java.html.geo-1.7-license.txt +++ b/platform/net.java.html.geo/external/net.java.html.geo-1.7.2-license.txt @@ -1,5 +1,5 @@ Name: Html4J Geolocation API -Version: 1.7 +Version: 1.7.2 Description: Html4j Geolocation API License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.geo/nbproject/project.properties b/platform/net.java.html.geo/nbproject/project.properties index 480c76b7e549..e8aee4ff2039 100644 --- a/platform/net.java.html.geo/nbproject/project.properties +++ b/platform/net.java.html.geo/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.geo-1.7.jar=modules/net-java-html-geo.jar +release.external/net.java.html.geo-1.7.2.jar=modules/net-java-html-geo.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.geo/nbproject/project.xml b/platform/net.java.html.geo/nbproject/project.xml index 108708839b03..5b3e3ad64e04 100644 --- a/platform/net.java.html.geo/nbproject/project.xml +++ b/platform/net.java.html.geo/nbproject/project.xml @@ -28,7 +28,7 @@ net-java-html-geo.jar - external/net.java.html.geo-1.7.jar + external/net.java.html.geo-1.7.2.jar diff --git a/platform/net.java.html.json/external/binaries-list b/platform/net.java.html.json/external/binaries-list index d57f026e414f..d7014919159e 100644 --- a/platform/net.java.html.json/external/binaries-list +++ b/platform/net.java.html.json/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -881CBEB3FC964CBFD2C7DA9200E1C85CE1560E10 org.netbeans.html:net.java.html.json:1.7 +B801FD4A689F1443A108E79BBEA24893EB8F2935 org.netbeans.html:net.java.html.json:1.7.2 diff --git a/platform/net.java.html.json/external/net.java.html.json-1.7-license.txt b/platform/net.java.html.json/external/net.java.html.json-1.7.2-license.txt similarity index 99% rename from platform/net.java.html.json/external/net.java.html.json-1.7-license.txt rename to platform/net.java.html.json/external/net.java.html.json-1.7.2-license.txt index d242a7705ed8..bda3b88ae5b7 100644 --- a/platform/net.java.html.json/external/net.java.html.json-1.7-license.txt +++ b/platform/net.java.html.json/external/net.java.html.json-1.7.2-license.txt @@ -1,5 +1,5 @@ Name: Html4J JSON Model in Java -Version: 1.7 +Version: 1.7.2 Description: Html4j JSON Model in Java License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.json/nbproject/project.properties b/platform/net.java.html.json/nbproject/project.properties index 117501fc6007..6db4c3ee853e 100644 --- a/platform/net.java.html.json/nbproject/project.properties +++ b/platform/net.java.html.json/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.json-1.7.jar=modules/net-java-html-json.jar +release.external/net.java.html.json-1.7.2.jar=modules/net-java-html-json.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.json/nbproject/project.xml b/platform/net.java.html.json/nbproject/project.xml index 129a4bfaba62..526fa5d6da2d 100644 --- a/platform/net.java.html.json/nbproject/project.xml +++ b/platform/net.java.html.json/nbproject/project.xml @@ -28,7 +28,7 @@ net-java-html-json.jar - external/net.java.html.json-1.7.jar + external/net.java.html.json-1.7.2.jar diff --git a/platform/net.java.html.sound/external/binaries-list b/platform/net.java.html.sound/external/binaries-list index a8261d5fd055..26b939277a08 100644 --- a/platform/net.java.html.sound/external/binaries-list +++ b/platform/net.java.html.sound/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -2AE13EC63325542A90A944D438B830343C954058 org.netbeans.html:net.java.html.sound:1.7 +A6B3198F8987B4486EE62601DF212840FC9D3B41 org.netbeans.html:net.java.html.sound:1.7.2 diff --git a/platform/net.java.html.sound/external/net.java.html.sound-1.7-license.txt b/platform/net.java.html.sound/external/net.java.html.sound-1.7.2-license.txt similarity index 99% rename from platform/net.java.html.sound/external/net.java.html.sound-1.7-license.txt rename to platform/net.java.html.sound/external/net.java.html.sound-1.7.2-license.txt index 95fba485722c..c569638d26dd 100644 --- a/platform/net.java.html.sound/external/net.java.html.sound-1.7-license.txt +++ b/platform/net.java.html.sound/external/net.java.html.sound-1.7.2-license.txt @@ -1,5 +1,5 @@ Name: Html4J Sound API via HTML -Version: 1.7 +Version: 1.7.2 Description: Html4j Sound API via HTML License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.sound/nbproject/project.properties b/platform/net.java.html.sound/nbproject/project.properties index c6e1d2ba64ff..f2cdb1c42cc3 100644 --- a/platform/net.java.html.sound/nbproject/project.properties +++ b/platform/net.java.html.sound/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.sound-1.7.jar=modules/net-java-html-sound.jar +release.external/net.java.html.sound-1.7.2.jar=modules/net-java-html-sound.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.sound/nbproject/project.xml b/platform/net.java.html.sound/nbproject/project.xml index a71ac233a450..2015c8f75cd2 100644 --- a/platform/net.java.html.sound/nbproject/project.xml +++ b/platform/net.java.html.sound/nbproject/project.xml @@ -28,7 +28,7 @@ net-java-html-sound.jar - external/net.java.html.sound-1.7.jar + external/net.java.html.sound-1.7.2.jar diff --git a/platform/net.java.html/external/binaries-list b/platform/net.java.html/external/binaries-list index 5e8232f754ee..8bc1decc3ca3 100644 --- a/platform/net.java.html/external/binaries-list +++ b/platform/net.java.html/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -CCD6BDB95D674D5DB9189B146078CB0452CE1307 org.netbeans.html:net.java.html:1.7 +FD957A7BD4652EED5F4E982B186CAB036BA2DBBE org.netbeans.html:net.java.html:1.7.2 diff --git a/platform/net.java.html/external/net.java.html-1.7-license.txt b/platform/net.java.html/external/net.java.html-1.7.2-license.txt similarity index 99% rename from platform/net.java.html/external/net.java.html-1.7-license.txt rename to platform/net.java.html/external/net.java.html-1.7.2-license.txt index 31be8bea9e8c..c443c03d3a67 100644 --- a/platform/net.java.html/external/net.java.html-1.7-license.txt +++ b/platform/net.java.html/external/net.java.html-1.7.2-license.txt @@ -1,5 +1,5 @@ Name: Html4J -Version: 1.7 +Version: 1.7.2 Description: Html4j License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html/nbproject/project.properties b/platform/net.java.html/nbproject/project.properties index 58712d4c9f7f..53d7f24863a8 100644 --- a/platform/net.java.html/nbproject/project.properties +++ b/platform/net.java.html/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html-1.7.jar=modules/net-java-html.jar +release.external/net.java.html-1.7.2.jar=modules/net-java-html.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html/nbproject/project.xml b/platform/net.java.html/nbproject/project.xml index 3d7fa960a361..fd8ddd0ac387 100644 --- a/platform/net.java.html/nbproject/project.xml +++ b/platform/net.java.html/nbproject/project.xml @@ -28,7 +28,7 @@ net-java-html.jar - external/net.java.html-1.7.jar + external/net.java.html-1.7.2.jar diff --git a/platform/o.n.html.ko4j/external/binaries-list b/platform/o.n.html.ko4j/external/binaries-list index 274685b3e47c..f89b1d52c873 100644 --- a/platform/o.n.html.ko4j/external/binaries-list +++ b/platform/o.n.html.ko4j/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -BB182922EE11EFF2508BD0DB4144F468688EAA84 org.netbeans.html:ko4j:1.7 +87D636A969271FD9207959D17AA64ADA68523774 org.netbeans.html:ko4j:1.7.2 diff --git a/platform/o.n.html.ko4j/external/ko4j-1.7-license.txt b/platform/o.n.html.ko4j/external/ko4j-1.7.2-license.txt similarity index 99% rename from platform/o.n.html.ko4j/external/ko4j-1.7-license.txt rename to platform/o.n.html.ko4j/external/ko4j-1.7.2-license.txt index b8471e10c313..f09f029d17d9 100644 --- a/platform/o.n.html.ko4j/external/ko4j-1.7-license.txt +++ b/platform/o.n.html.ko4j/external/ko4j-1.7.2-license.txt @@ -1,5 +1,5 @@ Name: Knockout4J -Version: 1.7 +Version: 1.7.2 Description: Knockout4J License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/o.n.html.ko4j/nbproject/project.properties b/platform/o.n.html.ko4j/nbproject/project.properties index 896212e8d36e..a766d53d3fe1 100644 --- a/platform/o.n.html.ko4j/nbproject/project.properties +++ b/platform/o.n.html.ko4j/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/ko4j-1.7.jar=modules/org-netbeans-html-ko4j.jar +release.external/ko4j-1.7.2.jar=modules/org-netbeans-html-ko4j.jar nbm.module.author=Jaroslav Tulach is.autoload=true diff --git a/platform/o.n.html.ko4j/nbproject/project.xml b/platform/o.n.html.ko4j/nbproject/project.xml index afd15cedeb0e..c5a909fdf450 100644 --- a/platform/o.n.html.ko4j/nbproject/project.xml +++ b/platform/o.n.html.ko4j/nbproject/project.xml @@ -28,7 +28,7 @@ org-netbeans-html-ko4j.jar - external/ko4j-1.7.jar + external/ko4j-1.7.2.jar diff --git a/platform/o.n.html.xhr4j/external/binaries-list b/platform/o.n.html.xhr4j/external/binaries-list index ba27f8a62d81..c0102f9a8d6f 100644 --- a/platform/o.n.html.xhr4j/external/binaries-list +++ b/platform/o.n.html.xhr4j/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -736744D6DD34CAE10FE4EA1D4E33BBA595480A17 org.netbeans.html:xhr4j:1.7 +9EB95313E0BA7AE774B5FB25C5429EF2DEEB2B5A org.netbeans.html:xhr4j:1.7.2 diff --git a/platform/o.n.html.xhr4j/external/xhr4j-1.7-license.txt b/platform/o.n.html.xhr4j/external/xhr4j-1.7.2-license.txt similarity index 99% rename from platform/o.n.html.xhr4j/external/xhr4j-1.7-license.txt rename to platform/o.n.html.xhr4j/external/xhr4j-1.7.2-license.txt index 4a2691dc6a91..a926af524cfa 100644 --- a/platform/o.n.html.xhr4j/external/xhr4j-1.7-license.txt +++ b/platform/o.n.html.xhr4j/external/xhr4j-1.7.2-license.txt @@ -1,5 +1,5 @@ Name: XHR via Java -Version: 1.7 +Version: 1.7.2 Description: XHR via Java License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/o.n.html.xhr4j/nbproject/project.properties b/platform/o.n.html.xhr4j/nbproject/project.properties index c7c94e0b06fc..5cfe84c9ab33 100644 --- a/platform/o.n.html.xhr4j/nbproject/project.properties +++ b/platform/o.n.html.xhr4j/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/xhr4j-1.7.jar=modules/org-netbeans-html-xhr4j.jar +release.external/xhr4j-1.7.2.jar=modules/org-netbeans-html-xhr4j.jar nbm.module.author=Jaroslav Tulach is.autoload=true diff --git a/platform/o.n.html.xhr4j/nbproject/project.xml b/platform/o.n.html.xhr4j/nbproject/project.xml index 784280af8562..cb53b90f2649 100644 --- a/platform/o.n.html.xhr4j/nbproject/project.xml +++ b/platform/o.n.html.xhr4j/nbproject/project.xml @@ -28,7 +28,7 @@ org-netbeans-html-xhr4j.jar - external/xhr4j-1.7.jar + external/xhr4j-1.7.2.jar From 9028ce1c8b5007e5ad9381f7f92472bb90d8f3cc Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Sun, 19 Sep 2021 06:30:21 +0200 Subject: [PATCH 02/38] Including org.netbeans.html.presenter.generic HTML/Java module in the build --- nbbuild/cluster.properties | 1 + platform/generic/build.xml | 25 +++ platform/generic/external/binaries-list | 17 ++ .../external/generic-1.7.2-license.txt | 208 ++++++++++++++++++ platform/generic/manifest.mf | 1 + platform/generic/nbproject/project.properties | 19 ++ platform/generic/nbproject/project.xml | 35 +++ 7 files changed, 306 insertions(+) create mode 100644 platform/generic/build.xml create mode 100644 platform/generic/external/binaries-list create mode 100644 platform/generic/external/generic-1.7.2-license.txt create mode 100644 platform/generic/manifest.mf create mode 100644 platform/generic/nbproject/project.properties create mode 100644 platform/generic/nbproject/project.xml diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties index 66582daaa6aa..f8a9cf657e02 100644 --- a/nbbuild/cluster.properties +++ b/nbbuild/cluster.properties @@ -262,6 +262,7 @@ nb.cluster.platform=\ o.apache.commons.io,\ o.apache.commons.logging,\ o.n.core,\ + generic,\ o.n.html.ko4j,\ o.n.html.xhr4j,\ o.n.swing.laf.dark,\ diff --git a/platform/generic/build.xml b/platform/generic/build.xml new file mode 100644 index 000000000000..28e98611a16b --- /dev/null +++ b/platform/generic/build.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/platform/generic/external/binaries-list b/platform/generic/external/binaries-list new file mode 100644 index 000000000000..eb826dc566bc --- /dev/null +++ b/platform/generic/external/binaries-list @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +1CF79022EC9B51258719250B31A55F0E1F2F7F76 org.netbeans.html:generic:1.7.2 diff --git a/platform/generic/external/generic-1.7.2-license.txt b/platform/generic/external/generic-1.7.2-license.txt new file mode 100644 index 000000000000..f09f029d17d9 --- /dev/null +++ b/platform/generic/external/generic-1.7.2-license.txt @@ -0,0 +1,208 @@ +Name: Knockout4J +Version: 1.7.2 +Description: Knockout4J +License: Apache-2.0 +Origin: Apache Software Foundation +URL: http://incubator.apache.org/projects/netbeans.html + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/platform/generic/manifest.mf b/platform/generic/manifest.mf new file mode 100644 index 000000000000..6c3938bd2090 --- /dev/null +++ b/platform/generic/manifest.mf @@ -0,0 +1 @@ +OpenIDE-Module: generic diff --git a/platform/generic/nbproject/project.properties b/platform/generic/nbproject/project.properties new file mode 100644 index 000000000000..53f597ef2f83 --- /dev/null +++ b/platform/generic/nbproject/project.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +release.external/generic-1.7.2.jar=modules/generic.jar +nbm.module.author=Jaroslav Tulach +is.autoload=true diff --git a/platform/generic/nbproject/project.xml b/platform/generic/nbproject/project.xml new file mode 100644 index 000000000000..837baf84f887 --- /dev/null +++ b/platform/generic/nbproject/project.xml @@ -0,0 +1,35 @@ + + + + org.netbeans.modules.apisupport.project + + + generic + + + + generic.jar + external/generic-1.7.2.jar + + + + From 6919f2e909d198df3bb833c827b59f01e665c2b4 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Sun, 19 Sep 2021 06:31:54 +0200 Subject: [PATCH 03/38] Introducing pluggable HTML viewer SPI --- platform/api.htmlui/manifest.mf | 2 +- platform/api.htmlui/nbproject/project.xml | 1 + .../modules/htmlui/HtmlComponent.java | 42 ++++++------ .../org/netbeans/modules/htmlui/HtmlPair.java | 68 +++++++++++++++++++ .../org/netbeans/modules/htmlui/Pages.java | 33 +++++---- .../org/netbeans/spi/htmlui/HtmlViewer.java | 33 +++++++++ 6 files changed, 147 insertions(+), 32 deletions(-) create mode 100644 platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java create mode 100644 platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java diff --git a/platform/api.htmlui/manifest.mf b/platform/api.htmlui/manifest.mf index a704f0aa551f..75f253fe8f9c 100644 --- a/platform/api.htmlui/manifest.mf +++ b/platform/api.htmlui/manifest.mf @@ -1,5 +1,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.api.htmlui OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/htmlui/Bundle.properties -OpenIDE-Module-Specification-Version: 1.20 +OpenIDE-Module-Specification-Version: 1.21 diff --git a/platform/api.htmlui/nbproject/project.xml b/platform/api.htmlui/nbproject/project.xml index 276307bdc18d..4ec7b39b8372 100644 --- a/platform/api.htmlui/nbproject/project.xml +++ b/platform/api.htmlui/nbproject/project.xml @@ -146,6 +146,7 @@ org.netbeans.api.htmlui + org.netbeans.spi.htmlui diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java index 107bf5a538b1..78dd904dd486 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java @@ -18,6 +18,7 @@ */ package org.netbeans.modules.htmlui; +import org.netbeans.spi.htmlui.HtmlViewer; import java.awt.BorderLayout; import java.io.Closeable; import java.io.IOException; @@ -29,11 +30,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; import java.util.logging.Level; import javax.swing.JComponent; import net.java.html.js.JavaScriptBody; import static org.netbeans.modules.htmlui.HtmlToolkit.LOG; -import org.openide.util.Lookup; import org.openide.util.lookup.AbstractLookup; import org.openide.util.lookup.InstanceContent; import org.openide.windows.TopComponent; @@ -46,7 +47,7 @@ persistenceType = TopComponent.PERSISTENCE_NEVER, preferredID = "browser" ) -public final class HtmlComponent extends TopComponent { +public final class HtmlComponent extends TopComponent { private final JComponent p = HtmlToolkit.getDefault().newPanel(); private /* final */ Object webView; private final InstanceContent ic; @@ -60,26 +61,21 @@ public final class HtmlComponent extends TopComponent { add(p, BorderLayout.CENTER); } - public void loadFX(URL pageUrl, final Class clazz, final String m, Object... ctx) { + void loadFX(ClassLoader loader, URL pageUrl, Callable init, String... ctx) { webView = HtmlToolkit.getDefault().initHtmlComponent(p, this::setDisplayName); - ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class); - if (loader == null) { - loader = clazz.getClassLoader(); - } HtmlToolkit.getDefault().load(webView, pageUrl, new Runnable() { @Override public void run() { try { HtmlComponent hc = HtmlComponent.this; - Method method = clazz.getMethod(m); - Object value = method.invoke(null); + value = init.call(); if (value != null) { hc.value = value; hc.ic.add(value); } listenOnContext(hc); } catch (Exception ex) { - LOG.log(Level.WARNING, "Can't load " + m + " from " + clazz, ex); + LOG.log(Level.WARNING, "Can't load " + pageUrl, ex); } } }, loader, ctx); @@ -97,7 +93,7 @@ final void onChange(Object[] values) { if (o instanceof String) { Object inst = c.remove((String)o); if (inst == null) try { - Class cookie = loadClass((String) o); + Class cookie = HtmlPair.loadClass((String) o); Constructor[] arr = cookie.getConstructors(); if (arr.length != 1) { LOG.log(Level.WARNING, "Class {0} should have one public constructor. Found {1}", new Object[]{cookie, Arrays.toString(arr)}); @@ -143,14 +139,22 @@ final void onChange(Object[] values) { ) private static native void listenOnContext(HtmlComponent onChange); - static Class loadClass(String c) throws ClassNotFoundException { - ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class); - if (l == null) { - l = Thread.currentThread().getContextClassLoader(); + static final HtmlViewer VIEWER = new HtmlViewer() { + @Override + public HtmlComponent newView() { + return new HtmlComponent(); } - if (l == null) { - l = Pages.class.getClassLoader(); + + @Override + public void makeVisible(HtmlComponent view, Runnable whenReady) { + view.open(); + view.requestActive(); + HtmlToolkit.getDefault().execute(whenReady); } - return Class.forName(c, true, l); - } + + @Override + public void load(HtmlComponent view, ClassLoader loader, URL pageUrl, Callable initialize, String[] techIds) { + view.loadFX(loader, pageUrl, initialize, techIds); + } + }; } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java new file mode 100644 index 000000000000..6245f19b6fce --- /dev/null +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.htmlui; + +import org.netbeans.spi.htmlui.HtmlViewer; +import java.net.URL; +import java.util.concurrent.Callable; +import org.openide.util.Lookup; + +final class HtmlPair { + private final HtmlViewer viewer; + private final HtmlView view; + + HtmlPair(HtmlViewer viewer, HtmlView view) { + this.viewer = viewer; + this.view = view; + } + + static Class loadClass(String c) throws ClassNotFoundException { + ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class); + if (l == null) { + l = Thread.currentThread().getContextClassLoader(); + } + if (l == null) { + l = Pages.class.getClassLoader(); + } + return Class.forName(c, true, l); + } + + static HtmlPair newView() { + for (HtmlViewer viewer : Lookup.getDefault().lookupAll(HtmlViewer.class)) { + HtmlPair pair = newView(viewer); + if (pair != null) { + return pair; + } + } + return newView(HtmlComponent.VIEWER); + } + + private static HtmlPair newView(HtmlViewer viewer) { + final HtmlView view = viewer.newView(); + return view == null ? null : new HtmlPair<>(viewer, view); + } + + final void makeVisible(Runnable whenReady) { + viewer.makeVisible(view, whenReady); + } + + final void load(ClassLoader loader, URL pageUrl, Callable initialize, String... techIds) { + viewer.load(view, loader, pageUrl, initialize, techIds); + } +} diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Pages.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Pages.java index 93c4e101f08f..a29b39774211 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Pages.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Pages.java @@ -20,12 +20,14 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.awt.Actions; +import org.openide.util.Lookup; /** API for controlling HTML like UI from Java language. * @@ -44,11 +46,12 @@ public static Action openAction(final Map map) { Boolean.TRUE.equals(map.get("noIconInMenu")) // NOI18N ); } + static class R implements ActionListener, Runnable { private final Map map; - private String m; + private String methodName; private Class clazz; - private HtmlComponent tc; + private HtmlPair tc; private URL pageUrl; private List techIds; @@ -61,16 +64,13 @@ public void actionPerformed(ActionEvent e) { try { String u = (String) map.get("url"); String c = (String) map.get("class"); - m = (String) map.get("method"); + methodName = (String) map.get("method"); - clazz = HtmlComponent.loadClass(c); + clazz = HtmlPair.loadClass(c); pageUrl = new URL("nbresloc:/" + u); - tc = new HtmlComponent(); - tc.open(); - tc.requestActive(); - - HtmlToolkit.getDefault().execute(this); + tc = HtmlPair.newView(); + tc.makeVisible(this); } catch (Exception ex) { throw new IllegalStateException(ex); } @@ -78,10 +78,19 @@ public void actionPerformed(ActionEvent e) { @Override public void run() { - tc.loadFX(pageUrl, clazz, m, getTechIds()); + ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class); + if (loader == null) { + loader = clazz.getClassLoader(); + } + + tc.load(loader, pageUrl, () -> { + Method method = clazz.getMethod(methodName); + Object value = method.invoke(null); + return value; + }, getTechIds()); } - final Object[] getTechIds() { + final String[] getTechIds() { if (techIds == null) { techIds = new ArrayList<>(); for (int i = 0;; i++) { @@ -93,7 +102,7 @@ final Object[] getTechIds() { } } } - return techIds.toArray(); + return techIds.toArray(new String[0]); } } } diff --git a/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java b/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java new file mode 100644 index 000000000000..57e329fca7f6 --- /dev/null +++ b/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.spi.htmlui; + +import java.net.URL; +import java.util.concurrent.Callable; + +/** + * + * @param + * @since 1.21 + */ +public interface HtmlViewer { + public HtmlView newView(); + public void makeVisible(HtmlView view, Runnable whenReady); + public void load(HtmlView view, ClassLoader loader, URL pageUrl, Callable initialize, String[] techIds); +} From f517d189978c7c47658bdcbad6f733baf6b268b3 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 20 Sep 2021 09:53:28 +0200 Subject: [PATCH 04/38] HTML/Java UI API no longer depends on JavaFX and can be used on its own --- .travis.yml | 1 + nbbuild/cluster.properties | 3 +- platform/api.htmlui/nbproject/project.xml | 14 --- .../modules/htmlui/DefaultHtmlToolkit.java | 86 +++++++++++++++++++ .../modules/htmlui/HTMLDialogImpl.java | 1 + .../modules/htmlui/HtmlComponent.java | 6 +- .../org/netbeans/modules/htmlui/HtmlPair.java | 4 +- .../{modules => spi}/htmlui/HtmlToolkit.java | 25 +++--- .../org/netbeans/modules/htmlui/ATech.java | 2 +- platform/htmlui/build.xml | 5 ++ platform/htmlui/manifest.mf | 6 ++ platform/htmlui/nbproject/project.properties | 3 + platform/htmlui/nbproject/project.xml | 81 +++++++++++++++++ .../netbeans/modules/htmlui/Bundle.properties | 5 ++ .../modules/htmlui/jfx/JavaFxHtmlToolkit.java | 7 +- .../modules/htmlui/jfx/NbBrowsers.java | 0 .../modules/htmlui/jfx/NbFxPanel.java | 0 .../org/netbeans/modules/htmlui/ATech.java | 40 +++++++++ .../modules/htmlui/ComponentsTest.java | 3 +- .../netbeans/modules/htmlui/DialogsTest.java | 2 + .../modules/htmlui/EnsureJavaFXPresent.java | 2 +- .../modules/htmlui/HtmlComponentTest.java | 2 +- .../org/netbeans/modules/htmlui/NbResloc.java | 0 .../modules/htmlui/ShowDialogFromEDTTest.java | 0 .../htmlui/ShowDialogFromFXThreadTest.java | 0 .../org/netbeans/modules/htmlui/simple.html | 30 +++++++ 26 files changed, 290 insertions(+), 38 deletions(-) create mode 100644 platform/api.htmlui/src/org/netbeans/modules/htmlui/DefaultHtmlToolkit.java rename platform/api.htmlui/src/org/netbeans/{modules => spi}/htmlui/HtmlToolkit.java (60%) create mode 100644 platform/htmlui/build.xml create mode 100644 platform/htmlui/manifest.mf create mode 100644 platform/htmlui/nbproject/project.properties create mode 100644 platform/htmlui/nbproject/project.xml create mode 100644 platform/htmlui/src/org/netbeans/modules/htmlui/Bundle.properties rename platform/{api.htmlui => htmlui}/src/org/netbeans/modules/htmlui/jfx/JavaFxHtmlToolkit.java (97%) rename platform/{api.htmlui => htmlui}/src/org/netbeans/modules/htmlui/jfx/NbBrowsers.java (100%) rename platform/{api.htmlui => htmlui}/src/org/netbeans/modules/htmlui/jfx/NbFxPanel.java (100%) create mode 100644 platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ATech.java rename platform/{api.htmlui => htmlui}/test/unit/src/org/netbeans/modules/htmlui/ComponentsTest.java (98%) rename platform/{api.htmlui => htmlui}/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java (98%) rename platform/{api.htmlui => htmlui}/test/unit/src/org/netbeans/modules/htmlui/EnsureJavaFXPresent.java (97%) rename platform/{api.htmlui => htmlui}/test/unit/src/org/netbeans/modules/htmlui/HtmlComponentTest.java (98%) rename platform/{api.htmlui => htmlui}/test/unit/src/org/netbeans/modules/htmlui/NbResloc.java (100%) rename platform/{api.htmlui => htmlui}/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromEDTTest.java (100%) rename platform/{api.htmlui => htmlui}/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromFXThreadTest.java (100%) create mode 100644 platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/simple.html diff --git a/.travis.yml b/.travis.yml index 9e3022dad973..6ca960b00737 100644 --- a/.travis.yml +++ b/.travis.yml @@ -109,6 +109,7 @@ matrix: - ant $OPTS build script: - travis_retry hide-logs.sh ant $OPTS -f platform/api.htmlui test + - travis_retry hide-logs.sh ant $OPTS -f platform/htmlui test - hide-logs.sh ant $OPTS -f platform/api.intent test - hide-logs.sh ant $OPTS -f platform/api.io test - hide-logs.sh ant $OPTS -f platform/api.progress test diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties index f8a9cf657e02..9b878f23086b 100644 --- a/nbbuild/cluster.properties +++ b/nbbuild/cluster.properties @@ -226,6 +226,8 @@ nb.cluster.platform=\ editor.mimelookup,\ editor.mimelookup.impl,\ favorites,\ + generic,\ + htmlui,\ janitor,\ javahelp,\ junitlib,\ @@ -262,7 +264,6 @@ nb.cluster.platform=\ o.apache.commons.io,\ o.apache.commons.logging,\ o.n.core,\ - generic,\ o.n.html.ko4j,\ o.n.html.xhr4j,\ o.n.swing.laf.dark,\ diff --git a/platform/api.htmlui/nbproject/project.xml b/platform/api.htmlui/nbproject/project.xml index 4ec7b39b8372..18d338aa619d 100644 --- a/platform/api.htmlui/nbproject/project.xml +++ b/platform/api.htmlui/nbproject/project.xml @@ -37,12 +37,6 @@ - - net.java.html.boot.fx - - - - net.java.html.json @@ -57,14 +51,6 @@ org.netbeans.html.xhr4j - - org.netbeans.libs.javafx - - - - 2.4 - - org.netbeans.libs.asm diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/DefaultHtmlToolkit.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/DefaultHtmlToolkit.java new file mode 100644 index 000000000000..d75a2c539a53 --- /dev/null +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/DefaultHtmlToolkit.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.htmlui; + +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.net.URL; +import java.util.List; +import java.util.function.Consumer; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import org.netbeans.spi.htmlui.HtmlToolkit; +import org.openide.DialogDescriptor; + +public class DefaultHtmlToolkit extends HtmlToolkit { + public static final HtmlToolkit DEFAULT = new DefaultHtmlToolkit(); + + private DefaultHtmlToolkit() { + } + + @Override + public boolean isApplicationThread() { + return EventQueue.isDispatchThread(); + } + + @Override + public JComponent newPanel() { + JPanel p = new JPanel(); + p.setLayout(new BorderLayout()); + p.add(new JLabel("No JavaFX installed!"), BorderLayout.CENTER); + return p; + } + + @Override + public void load(Object webView, URL pageUrl, Runnable runnable, ClassLoader loader, Object... ctx) { + } + + @Override + public Object initHtmlComponent(JComponent p, Consumer titleDisplayer) { + return null; + } + + @Override + public Object initHtmlDialog(String page, DialogDescriptor dd, JComponent p, Runnable onPageLoad, List techIds) { + return null; + } + + @Override + public C convertToComponent(Class type, URL pageUrl, ClassLoader loader, Runnable onPageLoad, List techIds) { + return null; + } + + @Override + public void enterNestedLoop(Object aThis) { + } + + @Override + public void exitNestedLoop(Object aThis) { + } + + @Override + public void execute(Runnable command) { + if (EventQueue.isDispatchThread()) { + command.run(); + } else { + EventQueue.invokeLater(command); + } + } +} diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java index 5c4d7d1ba7c3..6e1bcbdb0e41 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java @@ -18,6 +18,7 @@ */ package org.netbeans.modules.htmlui; +import org.netbeans.spi.htmlui.HtmlToolkit; import java.awt.Dialog; import java.awt.Dimension; import java.awt.EventQueue; diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java index 78dd904dd486..78fe84900d46 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java @@ -18,12 +18,12 @@ */ package org.netbeans.modules.htmlui; +import org.netbeans.spi.htmlui.HtmlToolkit; import org.netbeans.spi.htmlui.HtmlViewer; import java.awt.BorderLayout; import java.io.Closeable; import java.io.IOException; import java.lang.reflect.Constructor; -import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; @@ -34,7 +34,7 @@ import java.util.logging.Level; import javax.swing.JComponent; import net.java.html.js.JavaScriptBody; -import static org.netbeans.modules.htmlui.HtmlToolkit.LOG; +import static org.netbeans.spi.htmlui.HtmlToolkit.LOG; import org.openide.util.lookup.AbstractLookup; import org.openide.util.lookup.InstanceContent; import org.openide.windows.TopComponent; @@ -61,7 +61,7 @@ public final class HtmlComponent extends TopComponent { add(p, BorderLayout.CENTER); } - void loadFX(ClassLoader loader, URL pageUrl, Callable init, String... ctx) { + public final void loadFX(ClassLoader loader, URL pageUrl, Callable init, String... ctx) { webView = HtmlToolkit.getDefault().initHtmlComponent(p, this::setDisplayName); HtmlToolkit.getDefault().load(webView, pageUrl, new Runnable() { @Override diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java index 6245f19b6fce..df101a9f993e 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java @@ -32,7 +32,7 @@ final class HtmlPair { this.view = view; } - static Class loadClass(String c) throws ClassNotFoundException { + static Class loadClass(String c) throws ClassNotFoundException { ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class); if (l == null) { l = Thread.currentThread().getContextClassLoader(); @@ -44,7 +44,7 @@ static Class loadClass(String c) throws ClassNotFoundException { } static HtmlPair newView() { - for (HtmlViewer viewer : Lookup.getDefault().lookupAll(HtmlViewer.class)) { + for (HtmlViewer viewer : Lookup.getDefault().lookupAll(HtmlViewer.class)) { HtmlPair pair = newView(viewer); if (pair != null) { return pair; diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlToolkit.java b/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlToolkit.java similarity index 60% rename from platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlToolkit.java rename to platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlToolkit.java index f33174346ea2..55ac42951299 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlToolkit.java +++ b/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlToolkit.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.htmlui; +package org.netbeans.spi.htmlui; import java.net.URL; import java.util.List; @@ -24,23 +24,28 @@ import java.util.function.Consumer; import java.util.logging.Logger; import javax.swing.JComponent; +import org.netbeans.modules.htmlui.DefaultHtmlToolkit; import org.openide.DialogDescriptor; import org.openide.util.Lookup; +/** + * + * @since 1.21 + */ public abstract class HtmlToolkit implements Executor { public static final Logger LOG = Logger.getLogger(HtmlToolkit.class.getName()); public static HtmlToolkit getDefault() { HtmlToolkit toolkit = Lookup.getDefault().lookup(HtmlToolkit.class); - return toolkit; + return toolkit == null ? DefaultHtmlToolkit.DEFAULT : toolkit; } - protected abstract boolean isApplicationThread(); - protected abstract JComponent newPanel(); - protected abstract void load(Object webView, URL pageUrl, Runnable runnable, ClassLoader loader, Object... ctx); - protected abstract Object initHtmlComponent(JComponent p, Consumer titleDisplayer); - protected abstract Object initHtmlDialog(String page, DialogDescriptor dd, JComponent p, Runnable onPageLoad, List techIds); - protected abstract C convertToComponent(Class type, URL pageUrl, ClassLoader loader, Runnable onPageLoad, List techIds); - protected abstract void enterNestedLoop(Object aThis); - protected abstract void exitNestedLoop(Object aThis); + public abstract boolean isApplicationThread(); + public abstract JComponent newPanel(); + public abstract void load(Object webView, URL pageUrl, Runnable runnable, ClassLoader loader, Object... ctx); + public abstract Object initHtmlComponent(JComponent p, Consumer titleDisplayer); + public abstract Object initHtmlDialog(String page, DialogDescriptor dd, JComponent p, Runnable onPageLoad, List techIds); + public abstract C convertToComponent(Class type, URL pageUrl, ClassLoader loader, Runnable onPageLoad, List techIds); + public abstract void enterNestedLoop(Object aThis); + public abstract void exitNestedLoop(Object aThis); } diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ATech.java b/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ATech.java index afc296693480..958ac776c529 100644 --- a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ATech.java +++ b/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ATech.java @@ -28,7 +28,7 @@ public static final class First implements ATech { @Contexts.Id("second") public static final class Second implements ATech { } - + @ServiceProvider(service = Contexts.Provider.class) public final static class Register implements Contexts.Provider { @Override diff --git a/platform/htmlui/build.xml b/platform/htmlui/build.xml new file mode 100644 index 000000000000..457774933a0a --- /dev/null +++ b/platform/htmlui/build.xml @@ -0,0 +1,5 @@ + + + Builds, tests, and runs the project org.netbeans.modules.htmlui + + diff --git a/platform/htmlui/manifest.mf b/platform/htmlui/manifest.mf new file mode 100644 index 000000000000..ef55e1e32d09 --- /dev/null +++ b/platform/htmlui/manifest.mf @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: true +OpenIDE-Module: org.netbeans.modules.htmlui +OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/htmlui/Bundle.properties +OpenIDE-Module-Specification-Version: 1.0 + diff --git a/platform/htmlui/nbproject/project.properties b/platform/htmlui/nbproject/project.properties new file mode 100644 index 000000000000..3733e602bf6e --- /dev/null +++ b/platform/htmlui/nbproject/project.properties @@ -0,0 +1,3 @@ +is.eager=true +javac.source=1.8 +javac.compilerargs=-Xlint -Xlint:-serial diff --git a/platform/htmlui/nbproject/project.xml b/platform/htmlui/nbproject/project.xml new file mode 100644 index 000000000000..d261200230f5 --- /dev/null +++ b/platform/htmlui/nbproject/project.xml @@ -0,0 +1,81 @@ + + + org.netbeans.modules.apisupport.project + + + org.netbeans.modules.htmlui + + + org.netbeans.api.htmlui + + + + 1.21 + + + + org.netbeans.libs.javafx + + + + 2.20 + + + + org.openide.dialogs + + + + 7.55 + + + + org.openide.util + + + + 9.21 + + + + org.openide.util.ui + + + + 9.21 + + + + org.openide.util.lookup + + + + 8.47 + + + + net.java.html.boot + + + + + + net.java.html.boot.fx + + + + + + + + unit + + org.netbeans.libs.testng + + + + + + + + diff --git a/platform/htmlui/src/org/netbeans/modules/htmlui/Bundle.properties b/platform/htmlui/src/org/netbeans/modules/htmlui/Bundle.properties new file mode 100644 index 000000000000..bc280e61eb4b --- /dev/null +++ b/platform/htmlui/src/org/netbeans/modules/htmlui/Bundle.properties @@ -0,0 +1,5 @@ +OpenIDE-Module-Display-Category=Infrastructure +OpenIDE-Module-Long-Description=\ + Provides necessary infrastructure (based on JavaFX WebView) to mix HTML based user interfaces together with classical Swing chrome of the NetBeans applications. +OpenIDE-Module-Name=HTML UI Implementation +OpenIDE-Module-Short-Description=Support for displaying HTML based UI diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/jfx/JavaFxHtmlToolkit.java b/platform/htmlui/src/org/netbeans/modules/htmlui/jfx/JavaFxHtmlToolkit.java similarity index 97% rename from platform/api.htmlui/src/org/netbeans/modules/htmlui/jfx/JavaFxHtmlToolkit.java rename to platform/htmlui/src/org/netbeans/modules/htmlui/jfx/JavaFxHtmlToolkit.java index e20d015a9d8d..b083a4c8642c 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/jfx/JavaFxHtmlToolkit.java +++ b/platform/htmlui/src/org/netbeans/modules/htmlui/jfx/JavaFxHtmlToolkit.java @@ -18,7 +18,7 @@ */ package org.netbeans.modules.htmlui.jfx; -import org.netbeans.modules.htmlui.HtmlToolkit; +import org.netbeans.spi.htmlui.HtmlToolkit; import java.awt.EventQueue; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -38,9 +38,8 @@ import javafx.scene.web.WebView; import javafx.stage.Stage; import javax.swing.JComponent; -import org.netbeans.modules.htmlui.HTMLDialogImpl; import org.openide.DialogDescriptor; -import org.openide.util.Lookup; +import org.openide.util.*; import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = HtmlToolkit.class) @@ -121,7 +120,7 @@ public void run() { ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class); if (loader == null) { - loader = HTMLDialogImpl.class.getClassLoader(); + loader = JavaFxHtmlToolkit.class.getClassLoader(); } URL pageUrl; try { diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/jfx/NbBrowsers.java b/platform/htmlui/src/org/netbeans/modules/htmlui/jfx/NbBrowsers.java similarity index 100% rename from platform/api.htmlui/src/org/netbeans/modules/htmlui/jfx/NbBrowsers.java rename to platform/htmlui/src/org/netbeans/modules/htmlui/jfx/NbBrowsers.java diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/jfx/NbFxPanel.java b/platform/htmlui/src/org/netbeans/modules/htmlui/jfx/NbFxPanel.java similarity index 100% rename from platform/api.htmlui/src/org/netbeans/modules/htmlui/jfx/NbFxPanel.java rename to platform/htmlui/src/org/netbeans/modules/htmlui/jfx/NbFxPanel.java diff --git a/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ATech.java b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ATech.java new file mode 100644 index 000000000000..958ac776c529 --- /dev/null +++ b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ATech.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.htmlui; + +import org.netbeans.html.context.spi.Contexts; +import org.openide.util.lookup.ServiceProvider; + +public interface ATech { + @Contexts.Id("first") + public static final class First implements ATech { + } + @Contexts.Id("second") + public static final class Second implements ATech { + } + + @ServiceProvider(service = Contexts.Provider.class) + public final static class Register implements Contexts.Provider { + @Override + public void fillContext(Contexts.Builder bldr, Class type) { + bldr.register(ATech.class, new First(), 30); + bldr.register(ATech.class, new Second(), 50); + } + } +} diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ComponentsTest.java b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ComponentsTest.java similarity index 98% rename from platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ComponentsTest.java rename to platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ComponentsTest.java index 9420f8f443bb..21796f61545e 100644 --- a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ComponentsTest.java +++ b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ComponentsTest.java @@ -18,6 +18,7 @@ */ package org.netbeans.modules.htmlui; +import org.netbeans.modules.htmlui.EnsureJavaFXPresent; import java.util.concurrent.CountDownLatch; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; @@ -86,7 +87,7 @@ public void run() { url = "simple.html", className = "TestPages", type = JComponent.class, techIds = "second" - ) + ) static void getSwing(int param, CountDownLatch called) { assertEquals(param, 10, "Correct value passed in"); called.countDown(); diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java similarity index 98% rename from platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java rename to platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java index 562558385b29..1c3ec63c7231 100644 --- a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java +++ b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java @@ -18,6 +18,7 @@ */ package org.netbeans.modules.htmlui; +import org.netbeans.modules.htmlui.EnsureJavaFXPresent; import java.awt.EventQueue; import java.net.URL; import java.util.concurrent.CountDownLatch; @@ -30,6 +31,7 @@ import net.java.html.BrwsrCtx; import net.java.html.js.JavaScriptBody; import org.netbeans.api.htmlui.HTMLDialog; +import org.netbeans.spi.htmlui.HtmlToolkit; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import static org.testng.Assert.*; diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/EnsureJavaFXPresent.java b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/EnsureJavaFXPresent.java similarity index 97% rename from platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/EnsureJavaFXPresent.java rename to platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/EnsureJavaFXPresent.java index 48a439e24631..ffc5054f75bb 100644 --- a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/EnsureJavaFXPresent.java +++ b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/EnsureJavaFXPresent.java @@ -22,7 +22,7 @@ import static org.testng.AssertJUnit.assertNotNull; import org.testng.SkipException; -class EnsureJavaFXPresent { +public final class EnsureJavaFXPresent { private static final Throwable initError; static { Throwable t; diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/HtmlComponentTest.java b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/HtmlComponentTest.java similarity index 98% rename from platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/HtmlComponentTest.java rename to platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/HtmlComponentTest.java index c15b2eb39a66..f12bc4510f52 100644 --- a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/HtmlComponentTest.java +++ b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/HtmlComponentTest.java @@ -57,7 +57,7 @@ public static void initializeContext() throws Exception { Platform.runLater(new Runnable() { @Override public void run() { - tc.loadFX(u, HtmlComponentTest.class, "onLoad"); + tc.loadFX(HtmlComponentTest.class.getClassLoader(), u, HtmlComponentTest::onLoad); } }); lkp = tc.getLookup(); diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/NbResloc.java b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/NbResloc.java similarity index 100% rename from platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/NbResloc.java rename to platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/NbResloc.java diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromEDTTest.java b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromEDTTest.java similarity index 100% rename from platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromEDTTest.java rename to platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromEDTTest.java diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromFXThreadTest.java b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromFXThreadTest.java similarity index 100% rename from platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromFXThreadTest.java rename to platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/ShowDialogFromFXThreadTest.java diff --git a/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/simple.html b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/simple.html new file mode 100644 index 000000000000..29b32f334527 --- /dev/null +++ b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/simple.html @@ -0,0 +1,30 @@ + + + + + Empty + + + + + + From 683e3d78183ed0442a3240253c5c48d564e48b77 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 20 Sep 2021 10:28:15 +0200 Subject: [PATCH 05/38] Intercept requests to display an HTML UI and show it in VSCode's WebView --- .../nbcode/integration/nbproject/project.xml | 16 + .../nbcode/integration/LspHtmlViewer.java | 27 + java/java.lsp.server/nbproject/project.xml | 36 + .../java/lsp/server/htmlui/Browser.java | 707 ++++++++++++++++++ .../java/lsp/server/htmlui/HttpServer.java | 62 ++ .../java/lsp/server/htmlui/SimpleServer.java | 703 +++++++++++++++++ .../lsp/server/protocol/HtmlPageParams.java | 68 ++ .../server/protocol/NbCodeClientWrapper.java | 9 +- .../server/protocol/NbCodeLanguageClient.java | 14 +- .../java/lsp/server/protocol/Server.java | 5 + .../server/protocol/WorkspaceUIContext.java | 6 +- .../lsp/server/ui/AbstractLspHtmlViewer.java | 76 ++ .../server/ui/AbstractLspStatusDisplayer.java | 1 - .../modules/java/lsp/server/ui/UIContext.java | 10 + .../lsp/server/TestCodeLanguageClient.java | 109 +++ .../progress/TestProgressHandlerTest.java | 3 +- .../java/lsp/server/protocol/ServerTest.java | 45 +- .../ui/AbstractDialogDisplayerTest.java | 1 + java/java.lsp.server/vscode/src/extension.ts | 36 +- java/java.lsp.server/vscode/src/protocol.ts | 8 + 20 files changed, 1916 insertions(+), 26 deletions(-) create mode 100644 java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/LspHtmlViewer.java create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Browser.java create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/HttpServer.java create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/SimpleServer.java create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/HtmlPageParams.java create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java create mode 100644 java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java diff --git a/java/java.lsp.server/nbcode/integration/nbproject/project.xml b/java/java.lsp.server/nbcode/integration/nbproject/project.xml index 4c03c50d84c5..e5ef7cf595b6 100644 --- a/java/java.lsp.server/nbcode/integration/nbproject/project.xml +++ b/java/java.lsp.server/nbcode/integration/nbproject/project.xml @@ -51,6 +51,22 @@ 1.19 + + org.netbeans.api.htmlui + + + + 1.21 + + + + generic + + + + 1.7.2 + + org.netbeans.modules.java.lsp.server diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/LspHtmlViewer.java b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/LspHtmlViewer.java new file mode 100644 index 000000000000..91237894e7a3 --- /dev/null +++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/LspHtmlViewer.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.nbcode.integration; + +import org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer; +import org.netbeans.spi.htmlui.HtmlViewer; +import org.openide.util.lookup.ServiceProvider; + +@ServiceProvider(service = HtmlViewer.class) +public final class LspHtmlViewer extends AbstractLspHtmlViewer { +} diff --git a/java/java.lsp.server/nbproject/project.xml b/java/java.lsp.server/nbproject/project.xml index ce9ea039976e..4f76bbbc00fe 100644 --- a/java/java.lsp.server/nbproject/project.xml +++ b/java/java.lsp.server/nbproject/project.xml @@ -33,6 +33,18 @@ 2.7 + + net.java.html + + + + + + net.java.html.json + + + + org.netbeans.api.annotations.common @@ -60,6 +72,30 @@ 3.16 + + org.netbeans.api.htmlui + + + + 1.21 + + + + net.java.html.boot + + + + 1.7.2 + + + + generic + + + + 1.7.2 + + org.netbeans.api.io diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Browser.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Browser.java new file mode 100644 index 000000000000..ae395f2d869a --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Browser.java @@ -0,0 +1,707 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.java.lsp.server.htmlui; + +import java.io.Closeable; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.Flushable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLDecoder; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.UUID; +import java.util.concurrent.Executor; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.netbeans.html.boot.spi.Fn; +import org.netbeans.html.boot.spi.Fn.Presenter; +import org.netbeans.html.presenters.spi.ProtoPresenter; +import org.netbeans.html.presenters.spi.ProtoPresenterBuilder; +import org.openide.util.lookup.ServiceProvider; + +/** Browser based {@link Presenter}. It starts local server and + * launches browser that connects to it. Use {@link Browser.Config} to + * configure the actual browser to be started. + *

+ * To use this presenter specify following dependency: + *

+ * <dependency>
+ *   <groupId>org.netbeans.html.browser</groupId>
+ *   <artifactId>browser</artifactId>
+ *   <version>1.x</version>
+ * </dependency>
+ * 
+ */ +public abstract class Browser implements Fn.Presenter, Fn.KeepAlive, Flushable, +Executor, Closeable { + static final Logger LOG = Logger.getLogger(Browser.class.getName()); + private final Map SESSIONS = new HashMap<>(); + private final String app; + private HttpServer server; + private Runnable onPageLoad; + private Command current; + private final Config config; + private final Supplier> serverProvider; + + /** Default constructor. Reads configuration from properties. The actual browser to + * be launched can be influenced by value of + * com.dukescript.presenters.browser property. + * It can have following values: + *
    + *
  • GTK - use Gtk WebKit implementation. Requires presence of + * appropriate native libraries
  • + *
  • AWT - use {@link java.awt.Desktop#browse(java.net.URI)} to + * launch a browser
  • + *
  • NONE - just launches the server, useful together with + * com.dukescript.presenters.browserPort property that + * can specify a fixed port to open the server at + *
  • + *
  • any other value is interpreted as a command which is then + * launched on a command line with one parameter - the URL to connect to
  • + *
+ * If the property is not specified the system tries GTK mode first, + * followed by AWT and then tries to execute xdg-open + * (default LINUX command to launch a browser from a shell script). + *

+ * In addition to the above properties, it is possible to also enable + * debugging by setting com.dukescript.presenters.browserDebug=true. + * + * @throws Exception + */ + public Browser() { + this(new Config()); + } + + /** + * Browser configured by provided config. + * + * @param config the configuration + */ + public Browser(Config config) { + this(findCalleeClassName(), config, null); + } + + Browser(String app, Config config, Supplier> serverProvider) { + this.serverProvider = serverProvider != null ? serverProvider : SimpleServer::new; + this.app = app; + this.config = new Config(config); + } + + @Override + public final void execute(final Runnable r) { + current.execute(r); + } + + @Override + public void close() throws IOException { + if (server != null) { + server.shutdownNow(); + } + } + + HttpServer server() { + return server; + } + + static HttpServer findServer(Object obj) { + Command c; + if (obj instanceof Command) { + c = (Command) obj; + } else if (obj instanceof ProtoPresenter) { + c = ((ProtoPresenter) obj).lookup(Command.class); + } else { + throw new IllegalArgumentException("Cannot find server for " + obj); + } + return c.browser.server(); + } + + /** Shows URL in a browser. + * @param page the page to display in the browser + * @throws IOException if something goes wrong + */ + protected abstract void show(URI page) throws IOException; + + @Override + public Fn defineFn(String string, String... strings) { + throw new UnsupportedOperationException(); + } + + @Override + public void loadScript(Reader reader) throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + public Fn defineFn(String string, String[] strings, boolean[] blns) { + throw new UnsupportedOperationException(); + } + + @Override + public void flush() throws IOException { + throw new UnsupportedOperationException(); + } + + private static URI pageURL(String protocol, HttpServer server, final String page) { + int port = server.getPort(); + try { + return new URI(protocol + "://localhost:" + port + page); + } catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } + + @Override + public final void displayPage(URL page, Runnable onPageLoad) { + try { + this.onPageLoad = onPageLoad; + this.server = serverProvider.get(); + int from = 8080; + int to = 65535; + int port = config.getPort(); + if (port != -1) { + from = to = port; + } + server.init(from, to); + + this.server.addHttpHandler(new RootPage(page), "/"); + server.start(); + + show(pageURL("http", server, "/")); + } catch (IOException ex) { + Logger.getLogger(Browser.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** Parameters to configure {@link Browser}. + * Create an instance and pass it + * to {@link Browser#Browser(org.netbeans.html.presenters.browser.Browser.Config) } + * constructor. + */ + public final static class Config { + String browser; + Integer port; + boolean debug = Boolean.getBoolean("com.dukescript.presenters.browserDebug"); + + /** + * Default constructor. + */ + public Config() { + } + + private Config(Config copy) { + this.browser = copy.browser; + this.port = copy.port; + this.debug = copy.debug; + } + + /** The command to use when invoking a browser. Possible values: + *

    + *
  • + * GTK - use Gtk WebKit implementation. Requires presence of appropriate native libraries + *
  • + *
  • + * AWT - use Desktop.browse(java.net.URI) to launch a browser + *
  • + *
  • + * NONE - just launches the server, useful together with {@link #port(int)} to specify a fixed port to open the server at + *
  • + *
  • + * any other value is interpreted as a command which is then launched on a command line with one parameter - the URL to connect to + *
  • + *
+ * + * @param executable browser to execute + * @return this instance + */ + public Config command(String executable) { + this.browser = executable; + return this; + } + + /** The port to start the server at. + * By default a random port is selected. + * @param port the port + * @return this instance + */ + public Config port(int port) { + this.port = port; + return this; + } + + /** Enable or disable debugging. The default value is taken from a property + * {@code com.dukescript.presenters.browserDebug}. If the property is + * not specified, then the default value is {@code false}. + * + * @param debug true or false + * @return this instance + * @since 1.8 + */ + public Config debug(boolean debug) { + this.debug = debug; + return this; + } + + final String getBrowser() { + if (browser != null) { + return browser; + } + return System.getProperty("com.dukescript.presenters.browser"); // NOI18N + } + + final int getPort() { + if (port != null) { + return port; + } + String browserPort = System.getProperty("com.dukescript.presenters.browserPort"); // NOI18N + try { + return Integer.parseInt(browserPort); + } catch (NumberFormatException ex) { + return -1; + } + } + } + + static void cors(HttpServer s, Response r) { + s.setCharacterEncoding(r, "UTF-8"); + s.addHeader(r, "Access-Control-Allow-Origin", "*"); + s.addHeader(r, "Access-Control-Allow-Credentials", "true"); + s.addHeader(r, "Access-Control-Allow-Headers", "Content-Type"); + s.addHeader(r, "Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); + } + + private final class RootPage extends HttpServer.Handler { + private final URL page; + + public RootPage(URL page) { + this.page = page; + } + + @Override + public void service(HttpServer server, Request rqst, Response rspns) throws IOException { + String path = server.getRequestURI(rqst); + cors(server, rspns); + if ("OPTIONS".equals(server.getMethod(rqst))) { // NOI18N + server.setStatus(rspns, 204); + server.addHeader(rspns, "Allow", "OPTIONS, GET, HEAD, POST, PUT"); // NOI18N + return; + } + if ("/".equals(path) || "index.html".equals(path)) { + Reader is; + String prefix = "http://" + server.getServerName(rqst) + ":" + server.getServerPort(rqst) + "/"; + Writer w = server.getWriter(rspns); + server.setContentType(rspns, "text/html"); + final Command cmd = new Command(server, Browser.this, prefix); + try { + is = new InputStreamReader(page.openStream()); + } catch (IOException ex) { + w.write(""); + w.write("

Browser

"); + w.write("
");
+                    emitScript(w, prefix, cmd.id);
+                    w.write("");
+                    w.close();
+                    return;
+                }
+                SESSIONS.put(cmd.id, cmd);
+                int state = 0;
+                for (;;) {
+                    int ch = is.read();
+                    if (ch == -1) {
+                        break;
+                    }
+                    char lower = Character.toLowerCase((char)ch);
+                    switch (state) {
+                        case 1000: break;
+                        case 0: if (lower == '<') state = 1; break;
+                        case 1: if (lower == 'b') state = 2;
+                            else if (lower != ' ' && lower != '\n') state = 0;
+                            break;
+                        case 2: if (lower == 'o') state = 3; else state = 0; break;
+                        case 3: if (lower == 'd') state = 4; else state = 0; break;
+                        case 4: if (lower == 'y') state = 5; else state = 0; break;
+                        case 5: if (lower == '>') state = 500;
+                            else if (lower != ' ' && lower != '\n') state = 0;
+                            break;
+                    }
+                    w.write((char)ch);
+                    if (state == 500) {
+                        emitScript(w, prefix, cmd.id);
+                        state = 1000;
+                    }
+                }
+                if (state != 1000) {
+                    emitScript(w, prefix, cmd.id);
+                }
+                is.close();
+                w.close();
+            } else if (path.equals("/command.js")) {
+                String id = server.getParameter(rqst, "id");
+                Command c = SESSIONS.get(id);
+                if (c == null) {
+                    server.getWriter(rspns).write("No command for " + id);
+                    server.setStatus(rspns, 404);
+                    return;
+                }
+                c.service(rqst, rspns);
+            } else {
+                if (path.startsWith("/")) {
+                    path = path.substring(1);
+                }
+                URL relative = new URL(page, path);
+                InputStream is;
+                URLConnection conn;
+                try {
+                    conn = relative.openConnection();
+                    is = conn.getInputStream();
+                } catch (FileNotFoundException ex) {
+                    server.setStatus(rspns, 404);
+                    return;
+                }
+                String found = null;
+                if (relative.getProtocol().equals("file")) {
+                    try {
+                        File file = new File(relative.toURI());
+                        found = Files.probeContentType(file.toPath());
+                    } catch (URISyntaxException | IOException ignore) {
+                    }
+                } else {
+                    found = conn.getContentType();
+                }
+                if (found == null || "content/unknown".equals(found)) {
+                    if (path.endsWith(".html")) {
+                        found = "text/html";
+                    }
+                    if (path.endsWith(".js")) {
+                        found = "text/javascript";
+                    }
+                    if (path.endsWith(".css")) {
+                        found = "text/css";
+                    }
+                }
+                if (found != null) {
+                    server.setContentType(rspns, found);
+                }
+                OutputStream out = server.getOutputStream(rspns);
+                for (;;) {
+                    int b = is.read();
+                    if (b == -1) {
+                        break;
+                    }
+                    out.write(b);
+                }
+                out.close();
+                is.close();
+            }
+        }
+
+        private void emitScript(Writer w, String prefix, String id) throws IOException {
+            w.write("  \n");
+        }
+    }
+
+    String createCallbackFn(String prefix, String id) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("this.toBrwsrSrvr = function(name, a1, a2, a3, a4) {\n"
+            + "var url = '").append(prefix).append("command.js?id=").append(id).append("&name=' + name;\n"
+            + "var body = 'p0=' + encodeURIComponent(a1);\n"
+            + "body += '&p1=' + encodeURIComponent(a2);\n"
+            + "body += '&p2=' + encodeURIComponent(a3);\n"
+            + "body += '&p3=' + encodeURIComponent(a4);\n"
+            + "var request = new XMLHttpRequest();\n"
+        );
+        if (Browser.this.config.debug) {
+            sb.append(""
+            + "console.log('PUT ... ' + body.substring(0, 80));\n"
+            + "var now = new Date().getTime();\n"
+            );
+        }
+        sb.append(""
+            + "request.open('PUT', url, false);\n"
+            + "request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');\n"
+            + "request.send(body);\n"
+            + "var txt = request.responseText;\n"
+        );
+        if (Browser.this.config.debug) {
+            sb.append(""
+            + "var then = new Date().getTime();\n"
+            + "if (txt && txt !== 'null') {\n"
+            + "  var cmd = document.getElementById('cmd');\n"
+            + "  if (cmd) cmd.innerHTML = txt.substring(0,80);\n"
+            + "}\n"
+            + "console.log('... PUT [' + (then - now) + 'ms]: ' + txt.substring(0, 80));\n"
+            );
+        }
+        sb.append(""
+            + "return txt;\n"
+            + "};\n"
+        );
+        return sb.toString();
+    }
+
+    private static String findCalleeClassName() {
+        StackTraceElement[] frames = new Exception().getStackTrace();
+        for (StackTraceElement e : frames) {
+            String cn = e.getClassName();
+            if (cn.startsWith("com.dukescript.presenters.")) { // NOI18N
+                continue;
+            }
+            if (cn.startsWith("org.netbeans.html.")) { // NOI18N
+                continue;
+            }
+            if (cn.startsWith("net.java.html.")) { // NOI18N
+                continue;
+            }
+            if (cn.startsWith("java.")) { // NOI18N
+                continue;
+            }
+            if (cn.startsWith("javafx.")) { // NOI18N
+                continue;
+            }
+            if (cn.startsWith("com.sun.")) { // NOI18N
+                continue;
+            }
+            return cn;
+        }
+        return "org.netbeans.html"; // NOI18N
+    }
+
+    private static final class Command extends Object
+    implements Executor {
+        private final HttpServer server;
+        private final Queue exec;
+        private final Browser browser;
+        private final String id;
+        private final String prefix;
+        private Runner RUNNER;
+        private Response suspended;
+        private boolean initialized;
+        private final ProtoPresenter presenter;
+
+        Command(HttpServer s, Browser browser, String prefix) {
+            this.server = s;
+            this.id = UUID.randomUUID().toString();
+            this.RUNNER = s.initializeRunner(this.id);
+            this.exec = new LinkedList<>();
+            this.prefix = prefix;
+            this.browser = browser;
+            this.presenter = ProtoPresenterBuilder.newBuilder().
+                preparator(this::callbackFn, true).
+                loadJavaScript(this::loadJS, false).
+                app(browser.app).
+                dispatcher(this, true).
+                displayer(this::displayPage).
+                logger(this::log).
+                type("Browser").
+                register(this).
+                build();
+        }
+
+        @Override
+        public final void execute(final Runnable r) {
+            server.runSafe(this.RUNNER, r, this.presenter);
+        }
+
+        final synchronized void add(Object obj) {
+            if (suspended != null) {
+                Response rqst = suspended;
+                server.resume(rqst, () -> {
+                    try (Writer w = server.getWriter(rqst)) {
+                        w.write(obj.toString());
+                    } catch (IOException ex) {
+                        LOG.log(Level.SEVERE, null, ex);
+                    }
+                });
+                suspended = null;
+                return;
+            }
+            exec.add(obj);
+        }
+
+        private synchronized Object take(Response rspns) {
+            Object o = exec.poll();
+            if (o != null) {
+                return o;
+            }
+            suspended = rspns;
+            server.suspend(rspns);
+            return null;
+        }
+
+        private synchronized boolean initialize(Response rspns) {
+            if (!initialized) {
+                initialized = true;
+                suspended = rspns;
+                server.suspend(rspns);
+                execute(browser.onPageLoad);
+                return true;
+            }
+            return false;
+        }
+
+        void service(Request rqst, Response rspns) throws IOException {
+            final String methodName = server.getParameter(rqst, "name");
+            server.setContentType(rspns, "text/javascript");
+            Writer w = server.getWriter(rspns);
+            if (methodName == null) {
+                if (initialize(rspns)) {
+                    return;
+                }
+                // send new request
+                Object obj = take(rspns);
+                if (obj == null) {
+                    LOG.log(Level.FINE, "Suspending response {0}", rspns);
+                    return;
+                }
+                final String s = obj.toString();
+                w.write(s);
+                LOG.log(Level.FINE, "Exec global: {0}", s);
+            } else {
+                List args = new ArrayList<>();
+                String body = server.getBody(rqst);
+                for (String p : body.split("&")) {
+                    if (p.length() >= 3) {
+                        args.add(URLDecoder.decode(p.substring(3), "UTF-8"));
+                    }
+                }
+                String res;
+                try {
+                    LOG.log(Level.FINE, "Call {0}", methodName + " with " + args);
+                    res = presenter.js2java(methodName,
+                        args.get(0), args.get(1), args.get(2), args.get(3)
+                    );
+                    LOG.log(Level.FINE, "Result: {0}", res);
+                } catch (Exception ex) {
+                    res = "error:" + ex.getMessage();
+                }
+                if (res != null) {
+                    w.write(res);
+                } else {
+                    w.write("null");
+                }
+            }
+            w.close();
+        }
+
+        void callbackFn(ProtoPresenterBuilder.OnPrepared onReady) {
+            String sb = this.browser.createCallbackFn(prefix, id);
+            add(sb);
+            onReady.callbackIsPrepared("toBrwsrSrvr");
+        }
+
+        private static Level findLevel(int priority) {
+            if (priority >= Level.SEVERE.intValue()) {
+                return Level.SEVERE;
+            }
+            if (priority >= Level.WARNING.intValue()) {
+                return Level.WARNING;
+            }
+            if (priority >= Level.INFO.intValue()) {
+                return Level.INFO;
+            }
+            return Level.FINE;
+        }
+
+        void log(int priority, String msg, Object... args) {
+            Level level = findLevel(priority);
+
+            if (args.length == 1 && args[0] instanceof Throwable) {
+                LOG.log(level, msg, (Throwable) args[0]);
+            } else {
+                LOG.log(level, msg, args);
+            }
+        }
+
+        final void loadJS(String js) {
+            add(js);
+        }
+
+        void dispatch(Runnable r) {
+            server.runSafe(RUNNER, r, null);
+        }
+
+
+        public void displayPage(URL url, Runnable r) {
+            throw new UnsupportedOperationException(url.toString());
+        }
+    } // end of Command
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/HttpServer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/HttpServer.java
new file mode 100644
index 000000000000..8f6fa86fb5cb
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/HttpServer.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.htmlui;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import org.netbeans.html.boot.spi.Fn;
+
+abstract class HttpServer {
+    abstract void init(int from, int to) throws IOException;
+    abstract void start() throws IOException;
+    abstract void shutdownNow();
+    abstract void addHttpHandler(Handler h, String path);
+    abstract int getPort();
+
+    abstract String getRequestURI(Request r);
+    abstract String getServerName(Request r);
+    abstract int getServerPort(Request r);
+    abstract String getParameter(Request r, String id);
+    abstract String getMethod(Request r);
+    abstract String getBody(Request r) throws IOException;
+    abstract String getHeader(Request r, String substring);
+
+    abstract Writer getWriter(Response r);
+    abstract void setContentType(Response r, String texthtml);
+    abstract void setStatus(Response r, int i);
+    abstract OutputStream getOutputStream(Response r);
+    abstract void suspend(Response r);
+    abstract void resume(Response r, Runnable runWhenResponseIsReady);
+    abstract void setCharacterEncoding(Response r, String utF8);
+    abstract void addHeader(Response r, String accessControlAllowOrigin, String string);
+
+    abstract  void send(WebSocket socket, String s);
+
+    abstract Runner initializeRunner(String id);
+    abstract void runSafe(Runner runner, Runnable code, Fn.Presenter presenter);
+
+    static abstract class Handler {
+        abstract  void service(HttpServer server, Request rqst, Response rspns) throws IOException;
+    }
+
+    static abstract class WebSocketApplication {
+        abstract  void onMessage(HttpServer server, WebSocket socket, String text);
+    }
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/SimpleServer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/SimpleServer.java
new file mode 100644
index 000000000000..441f3f199186
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/SimpleServer.java
@@ -0,0 +1,703 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.htmlui;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.InetSocketAddress;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedByInterruptException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.StandardCharsets;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.TreeMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.netbeans.html.boot.spi.Fn;
+
+final class SimpleServer extends HttpServer {
+    private final Map maps = new TreeMap<>((s1, s2) -> {
+        if (s1.length() != s2.length()) {
+            return s2.length() - s1.length();
+        }
+        return s2.compareTo(s1);
+    });
+    private int max;
+    private int min;
+    /**
+     * @GuardedBy("this")
+     */
+    private ServerSocketChannel server;
+    /**
+     * @GuardedBy("this")
+     */
+    private Selector connection;
+    /**
+     * @GuardedBy("this")
+     */
+    private Thread processor;
+    private final List pendingActions = new ArrayList<>();
+
+    private static final Pattern PATTERN_GET = Pattern.compile("(OPTIONS|HEAD|GET|POST|PUT|DELETE) */([^ \\?]*)(\\?[^ ]*)?");
+    private static final Pattern PATTERN_HOST = Pattern.compile(".*^Host: *(.*):([0-9]+)$", Pattern.MULTILINE);
+    private static final Pattern PATTERN_LENGTH = Pattern.compile(".*^Content-Length: ([0-9]+)$", Pattern.MULTILINE);
+    static final Logger LOG = Logger.getLogger(SimpleServer.class.getName());
+
+    SimpleServer() {
+    }
+
+    @Override
+    void addHttpHandler(Handler h, String path) {
+        if (!path.startsWith("/")) {
+            throw new IllegalStateException("Shall start with /: " + path);
+        }
+        maps.put(path.substring(1), h);
+    }
+
+    @Override
+    void init(int from, int to) throws IOException {
+        this.connection = Selector.open();
+        this.min = from;
+        this.max = to;
+    }
+
+    @Override
+    synchronized void start() throws IOException {
+        LOG.log(Level.INFO, "Listening for HTTP connections on port {0}", getServer().socket().getLocalPort());
+        processor = new Thread(this::mainLoop, "HTTP server");
+        processor.start();
+    }
+
+    private final synchronized Thread getProcessorThread() {
+        return processor;
+    }
+
+    final void assertThread() {
+        assert Thread.currentThread() == getProcessorThread();
+    }
+
+    @Override
+    String getRequestURI(ReqRes r) {
+        assertThread();
+        return "/" + r.url;
+    }
+
+    @Override
+    String getServerName(ReqRes r) {
+        assertThread();
+        return r.hostName;
+    }
+
+    @Override
+    int getServerPort(ReqRes r) {
+        assertThread();
+        return r.hostPort;
+    }
+
+    @Override
+    String getParameter(ReqRes r, String id) {
+        assertThread();
+        return (String) r.args.get(id);
+    }
+
+    @Override
+    String getMethod(ReqRes r) {
+        assertThread();
+        return r.method;
+    }
+
+    @Override
+    String getBody(ReqRes r) {
+        assertThread();
+        if (r.body == null) {
+            return "";
+        } else {
+            return new String(r.body.array(), StandardCharsets.UTF_8);
+        }
+    }
+
+    static int endOfHeader(String header) {
+        return header.indexOf("\r\n\r\n");
+    }
+
+    @Override
+    String getHeader(ReqRes r, String key) {
+        assertThread();
+        for (String l : r.header.split("\r\n")) {
+            if (l.isEmpty()) {
+                break;
+            }
+            if (l.startsWith(key + ":")) {
+                return l.substring(key.length() + 1).trim();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    Writer getWriter(ReqRes r) {
+        assertThread();
+        return r.writer;
+    }
+
+    @Override
+    void setContentType(ReqRes r, String contentType) {
+        assertThread();
+        r.contentType = contentType;
+    }
+
+    @Override
+    void setStatus(ReqRes r, int status) {
+        assertThread();
+        r.status = status;
+    }
+
+    @Override
+    OutputStream getOutputStream(ReqRes r) {
+        assertThread();
+        return r.os;
+    }
+
+    @Override
+    void suspend(ReqRes r) {
+        assertThread();
+        r.suspended = true;
+        r.updateOperations();
+    }
+
+    @Override
+    void resume(ReqRes r, Runnable whenReady) {
+        connectionWakeup(() -> {
+            assertThread();
+            r.suspended = false;
+            r.updateOperations();
+            whenReady.run();
+        });
+    }
+
+    @Override
+    void setCharacterEncoding(ReqRes r, String encoding) {
+        if (!encoding.equals("UTF-8")) {
+            throw new IllegalStateException(encoding);
+        }
+    }
+
+    @Override
+    void addHeader(ReqRes r, String name, String value) {
+        assertThread();
+        r.headers.put(name, value);
+    }
+
+    @Override
+     void send(WebSocket socket, String s) {
+    }
+
+    /**
+     * @return the port to listen to
+     */
+    @Override
+    public int getPort() {
+        try {
+            return getServer().socket().getLocalPort();
+        } catch (IOException ex) {
+            return -1;
+        }
+    }
+
+    synchronized void connectionWakeup(Runnable runOnMainLoop) {
+        Selector localConnection = this.connection;
+        this.pendingActions.add(runOnMainLoop);
+        if (localConnection != null) {
+            localConnection.wakeup();
+        }
+    }
+
+    private void mainLoop() {
+        ByteBuffer bb = ByteBuffer.allocate(2048);
+        while (Thread.currentThread() == getProcessorThread()) {
+            ServerSocketChannel localServer;
+            Selector localConnection;
+            Runnable[] pendings;
+
+            SocketChannel toClose = null;
+            try {
+                synchronized (this) {
+                    localServer = this.getServer();
+                    localConnection = this.connection;
+                    pendings = this.pendingActions.toArray(new Runnable[0]);
+                    this.pendingActions.clear();
+                }
+
+                LOG.log(Level.FINEST, "Before select status: open server{0}, open connection {1}, pending {2}",
+                        new Object[]{localServer.isOpen(), localConnection.isOpen(), pendings.length}
+                );
+
+                for (Runnable r : pendings) {
+                    r.run();
+                }
+
+                int amount = localConnection.select();
+
+                LOG.log(Level.FINEST, "After select: {0}", amount);
+                if (amount == 0) {
+                    LOG.log(Level.FINE, "No amount after select: {0}", amount);
+                }
+
+                Set readyKeys = localConnection.selectedKeys();
+                Iterator it = readyKeys.iterator();
+                while (it.hasNext()) {
+                    SelectionKey key = it.next();
+                    LOG.log(Level.FINEST, "Handling key {0}", key.attachment());
+                    it.remove();
+
+                    if (key.isAcceptable()) {
+                        try {
+                            SocketChannel channel = localServer.accept();
+                            channel.configureBlocking(false);
+                            SelectionKey another = channel.register(
+                                    localConnection, SelectionKey.OP_READ
+                            );
+                            another.attach(new ReadHeader());
+                        } catch (ClosedByInterruptException ex) {
+                            LOG.log(Level.WARNING, "Interrupted while accepting", ex);
+                            server.close();
+                            server = null;
+                            LOG.log(Level.INFO, "Accept server reset");
+                        }
+                    } else if (key.isReadable()) {
+                        ((Buffer) bb).clear();
+                        SocketChannel channel = (SocketChannel) key.channel();
+                        toClose = channel;
+                        channel.read(bb);
+                        ((Buffer) bb).flip();
+
+                        if (key.attachment() instanceof ReadHeader) {
+                            ReadHeader readHeader = (ReadHeader) key.attachment();
+                            ReqRes nextKey = readHeader.process(key, bb);
+                            if (nextKey != null) {
+                                key.attach(nextKey);
+                                nextKey.updateOperations();
+                            }
+                        } else if (key.attachment() instanceof ReqRes) {
+                            ReqRes req = (ReqRes) key.attachment();
+                            req.readBody(key, bb);
+                            req.updateOperations();
+                        }
+                    } else if (key.isWritable()) {
+                        SocketChannel channel = (SocketChannel) key.channel();
+                        toClose = channel;
+                        if (key.attachment() instanceof ReqRes) {
+                            ReqRes request = (ReqRes) key.attachment();
+                            WriteReply write = request.handle(channel);
+                            if (write != null) {
+                                key.attach(write);
+                                write.updateOperations();
+                            }
+                        } else if (key.attachment() instanceof WriteReply) {
+                            WriteReply write = (WriteReply) key.attachment();
+                            write.output(channel);
+                        }
+                    }
+                }
+            } catch (ThreadDeath td) {
+                throw td;
+            } catch (Throwable t) {
+                LOG.log(Level.SEVERE, "Exception while handling request", t);
+                if (toClose != null) {
+                    try {
+                        toClose.close();
+                    } catch (IOException ioEx) {
+                        LOG.log(Level.INFO, "While closing", ioEx);
+                    }
+                }
+            }
+        }
+
+        synchronized (this) {
+            try {
+                LOG.fine("Closing connection");
+                this.connection.close();
+                LOG.fine("Closing server");
+                this.getServer().close();
+            } catch (IOException ex) {
+                LOG.log(Level.WARNING, null, ex);
+            } finally {
+                notifyAll();
+            }
+        }
+        LOG.fine("All notified, exiting server");
+    }
+
+    private Handler findHandler(String url) {
+        LOG.log(Level.FINE, "Searching for handler for page {0}", url);
+        for (Map.Entry entry : maps.entrySet()) {
+            if (url.startsWith(entry.getKey())) {
+                return entry.getValue();
+            }
+        }
+        throw new IllegalStateException("No mapping for " + url + " among " + maps);
+    }
+
+    private static void parseArgs(final Map context, final String args) {
+        if (args != null) {
+            for (String arg : args.substring(1).split("&")) {
+                String[] valueAndKey = arg.split("=");
+
+                String key = valueAndKey[1].replaceAll("\\+", " ");
+                for (int idx = 0;;) {
+                    idx = key.indexOf("%", idx);
+                    if (idx == -1) {
+                        break;
+                    }
+                    int ch = Integer.parseInt(key.substring(idx + 1, idx + 3), 16);
+                    key = key.substring(0, idx) + (char) ch + key.substring(idx + 3);
+                    idx++;
+                }
+
+                context.put(valueAndKey[0], key);
+            }
+        }
+    }
+
+    @Override
+    public synchronized void shutdownNow() {
+        Thread inter = processor;
+        if (inter != null) {
+            processor = null;
+            LOG.fine("Processor cleaned");
+            inter.interrupt();
+            LOG.fine("Processor interrupted");
+            try {
+                wait(5000);
+            } catch (InterruptedException ex) {
+                LOG.log(Level.WARNING, null, ex);
+            }
+            LOG.fine("After waiting");
+        }
+    }
+
+    /**
+     * Computes todays's date .
+     */
+    static byte[] date(Date date) {
+        return date("Date: ", date != null ? date : new Date());
+    }
+
+    static byte[] date(String prefix, Date date) {
+        try {
+            DateFormat f = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.US);
+            f.setTimeZone(TimeZone.getTimeZone("GMT")); // NOI18N
+            return (prefix + f.format(date)).getBytes("utf-8");
+        } catch (UnsupportedEncodingException ex) {
+            LOG.log(Level.WARNING, ex.getMessage(), ex);
+            return new byte[0];
+        }
+    }
+
+    public synchronized ServerSocketChannel getServer() throws IOException {
+        if (server == null) {
+            ServerSocketChannel s = ServerSocketChannel.open();
+            s.configureBlocking(false);
+
+            Random random = new Random();
+            for (int i = min; i <= max; i++) {
+                int at = min + random.nextInt(max - min + 1);
+                InetSocketAddress address = new InetSocketAddress(at);
+                try {
+                    s.socket().bind(address);
+                } catch (IOException ex) {
+                    LOG.log(Level.FINE, "Cannot bind to " + at, ex);
+                    continue;
+                }
+                server = s;
+                break;
+            }
+
+            server.register(this.connection, SelectionKey.OP_ACCEPT);
+        }
+        return server;
+    }
+
+    final class Context implements ThreadFactory {
+
+        private final String id;
+        Executor RUN;
+        Thread RUNNER;
+
+        Context(String id) {
+            this.id = id;
+        }
+
+        @Override
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(r, "Processor for " + id);
+            RUNNER = t;
+            return t;
+        }
+    }
+
+    @Override
+    Context initializeRunner(String id) {
+        Context c = new Context(id);
+        c.RUN = Executors.newSingleThreadExecutor(c);
+        return c;
+    }
+
+    @Override
+    void runSafe(Context c, Runnable r, Fn.Presenter presenter) {
+        class Wrap implements Runnable {
+
+            @Override
+            public void run() {
+                if (presenter != null) {
+                    try ( Closeable c = Fn.activate(presenter)) {
+                        r.run();
+                    } catch (IOException ex) {
+                        // go on
+                    }
+                } else {
+                    r.run();
+                }
+            }
+        }
+        if (c.RUNNER == Thread.currentThread()) {
+            if (presenter != null) {
+                Runnable w = new Wrap();
+                w.run();
+            } else {
+                r.run();
+            }
+        } else {
+            Runnable w = new Wrap();
+            c.RUN.execute(w);
+        }
+    }
+
+    final class ReadHeader {
+
+        private final StringBuilder buffer = new StringBuilder();
+
+        final ReqRes process(SelectionKey key, ByteBuffer chunk) {
+            String text = new String(chunk.array(), 0, chunk.limit(), StandardCharsets.US_ASCII);
+            buffer.append(text);
+            int fullHeader = buffer.indexOf("\r\n\r\n");
+            if (fullHeader == -1) {
+                return null;
+            }
+            String header = text.substring(0, fullHeader);
+
+            Matcher m = PATTERN_GET.matcher(header);
+            String url = m.find() ? m.group(2) : null;
+            String args = url != null && m.groupCount() == 3 ? m.group(3) : null;
+            String method = m.group(1);
+
+            Map context;
+            if (args != null) {
+                Map c = new HashMap<>();
+                parseArgs(c, args);
+                context = Collections.unmodifiableMap(c);
+            } else {
+                context = Collections.emptyMap();
+            }
+
+            Matcher length = PATTERN_LENGTH.matcher(header);
+            ByteBuffer body = null;
+            if (length.find()) {
+                int contentLength = Integer.parseInt(length.group(1));
+                body = ByteBuffer.allocate(contentLength);
+                ((Buffer) chunk).position(fullHeader + 4);
+                body.put(chunk);
+            }
+
+            Handler h = findHandler(url);
+            Matcher hostMatch = PATTERN_HOST.matcher(header);
+            String host = null;
+            int port = -1;
+            if (hostMatch.find()) {
+                host = hostMatch.group(1);
+                port = Integer.parseInt(hostMatch.group(2));
+            }
+            if (host != null) {
+                LOG.log(Level.FINER, "Host {0}:{1}", new Object[]{host, port});
+            }
+            return new ReqRes(h, key, url, context, host, port, header, method, body);
+        }
+    }
+
+    final class ReqRes {
+
+        private final SelectionKey delegate;
+        private final Handler h;
+        final String url;
+        final String hostName;
+        final int hostPort;
+        final Map args;
+        final String header;
+        final String method;
+        final ByteBuffer body;
+        private final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        final Writer writer = new OutputStreamWriter(os, StandardCharsets.UTF_8);
+        final Map headers = new LinkedHashMap<>();
+        String contentType;
+        int status = 200;
+        boolean computed;
+        boolean suspended;
+
+        public ReqRes(
+                Handler h, SelectionKey delegate,
+                String url, Map args, String host,
+                int port, String header, String method, ByteBuffer body
+        ) {
+            this.h = h;
+            this.delegate = delegate;
+            this.url = url;
+            this.hostName = host;
+            this.hostPort = port;
+            this.header = header;
+            this.args = args;
+            this.method = method;
+            this.body = body;
+        }
+
+        void updateOperations() {
+            if (body != null && body.remaining() > 0) {
+                delegate.interestOps(SelectionKey.OP_READ);
+            } else if (suspended) {
+                delegate.interestOps(0);
+            } else {
+                delegate.interestOps(SelectionKey.OP_WRITE);
+            }
+        }
+
+        public WriteReply handle(SocketChannel channel) throws IOException {
+            if (!computed) {
+                computed = true;
+                h.service(SimpleServer.this, this, this);
+            }
+            if (suspended) {
+                channel.write(ByteBuffer.allocate(0));
+                return null;
+            }
+
+            if (contentType == null) {
+                contentType = "content/unknown"; // NOI18N
+            }
+
+            ByteBuffer bb = ByteBuffer.allocate(8192);
+            ((Buffer) bb).clear();
+
+            LOG.log(Level.FINE, "Serving page request {0}", url); // NOI18N
+            ((Buffer) bb).clear();
+            bb.put(("HTTP/1.1 " + status + "\r\n").getBytes());
+            bb.put("Connection: close\r\n".getBytes());
+            bb.put("Server: Browser presenter\r\n".getBytes());
+            bb.put(date(null));
+            bb.put("\r\n".getBytes());
+            bb.put(("Content-Type: " + contentType + "\r\n").getBytes());
+            for (Map.Entry entry : headers.entrySet()) {
+                bb.put((entry.getKey() + ":" + entry.getValue() + "\r\n").getBytes());
+            }
+            bb.put("Pragma: no-cache\r\nCache-control: no-cache\r\n".getBytes());
+            bb.put("\r\n".getBytes());
+            ((Buffer) bb).flip();
+
+            return new WriteReply(delegate, url, bb, ByteBuffer.wrap(toByteArray()));
+        }
+
+        byte[] toByteArray() throws IOException {
+            writer.close();
+            return os.toByteArray();
+        }
+
+        void readBody(SelectionKey key, ByteBuffer chunk) {
+            body.put(chunk);
+        }
+
+        @Override
+        public String toString() {
+            return "Request[" + method + ":" + url + "]";
+        }
+    }
+
+    final class WriteReply {
+
+        private final SelectionKey delegate;
+        private final String url;
+        private final ByteBuffer header;
+        private final ByteBuffer body;
+
+        WriteReply(SelectionKey delegate, String url, ByteBuffer header, ByteBuffer body) {
+            this.delegate = delegate;
+            this.url = url;
+            this.header = header;
+            this.body = body;
+        }
+
+        void updateOperations() {
+            delegate.interestOps(SelectionKey.OP_WRITE);
+        }
+
+        void output(SocketChannel channel) throws IOException {
+            try {
+                if (header.remaining() > 0) {
+                    channel.write(header);
+                    return;
+                }
+                if (body.remaining() > 0) {
+                    channel.write(body);
+                } else {
+                    channel.close();
+                }
+            } finally {
+                if (!channel.isOpen()) {
+                    LOG.log(Level.FINE, "channel for {0} not open, closing", url);
+                    delegate.attach(null);
+                    delegate.cancel();
+                }
+            }
+
+        }
+    }
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/HtmlPageParams.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/HtmlPageParams.java
new file mode 100644
index 000000000000..cf037d5444f5
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/HtmlPageParams.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.protocol;
+
+import java.util.Objects;
+import org.eclipse.xtext.xbase.lib.Pure;
+
+public class HtmlPageParams  {
+    private String uri;
+
+    public HtmlPageParams(String uri) {
+        this.uri = uri;
+    }
+
+    @Pure
+    public String getUri() {
+        return uri;
+    }
+
+    public HtmlPageParams setUri(String uri) {
+        this.uri = uri;
+        return this;
+    }
+
+    @Pure
+    @Override
+    public int hashCode() {
+        int hash = 5;
+        hash = 83 * hash + Objects.hashCode(this.uri);
+        return hash;
+    }
+
+    @Pure
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final HtmlPageParams other = (HtmlPageParams) obj;
+        if (!Objects.equals(this.uri, other.uri)) {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java
index 05520e0ee852..2917929b2535 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java
@@ -37,7 +37,7 @@
 /**
  * Convenience wrapper that binds language client's remote proxy together with
  * other useful methods. Will be sent out as THE client by the server core code.
- * 
+ *
  * @author sdedic
  */
 class NbCodeClientWrapper implements NbCodeLanguageClient {
@@ -65,6 +65,13 @@ public void showStatusBarMessage(ShowStatusMessageParams params) {
         remote.showStatusBarMessage(params);
     }
 
+    @Override
+    public void showHtmlPage(HtmlPageParams params) {
+        remote.showHtmlPage(params);
+    }
+
+
+
     @Override
     public CompletableFuture> showQuickPick(ShowQuickPickParams params) {
         return remote.showQuickPick(params);
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java
index c1b3923fd2dd..d9aeb798bd77 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java
@@ -32,17 +32,23 @@
  * @author sdedic
  */
 public interface NbCodeLanguageClient extends LanguageClient {
-    
+
     /**
      * Shows a message in the status bar. Log- and Info-type messages are shown "as is".
      * The other message types can be decorated by an icon according to {@link MessageParams#getType}.
      * The message will be hidden after specified number of milliseconds; 0 means the client
      * controls when the message is hidden.
-     * 
+     *
      * @param params message type and text.
      */
     @JsonNotification("window/showStatusBarMessage")
     public void showStatusBarMessage(@NonNull ShowStatusMessageParams params);
+    /**
+     * Shows an HTML based UI.
+     * @param params the URI of the page to show
+     */
+    @JsonNotification("window/showHtmlPage")
+    public void showHtmlPage(@NonNull HtmlPageParams params);
 
     /**
      * Shows a selection list allowing multiple selections.
@@ -83,7 +89,7 @@ public interface NbCodeLanguageClient extends LanguageClient {
     /**
      * Set text editor decoration to an array of code ranges.
      *
-     * @param params 
+     * @param params
      */
     @JsonNotification("window/setTextEditorDecoration")
     public void setTextEditorDecoration(@NonNull SetTextEditorDecorationParams params);
@@ -101,7 +107,7 @@ public interface NbCodeLanguageClient extends LanguageClient {
      * @return code capabilities.
      */
     public NbCodeClientCapabilities getNbCodeCapabilities();
-    
+
     public default boolean isRequestDispatcherThread() {
         return Boolean.TRUE.equals(Server.DISPATCHERS.get());
     }
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
index 652c8602fe70..fbce8d608cef 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
@@ -861,6 +861,11 @@ public void disposeTextEditorDecoration(String params) {
         public void logMessage(MessageParams message) {
             logWarning(message);
         }
+
+        @Override
+        public void showHtmlPage(HtmlPageParams params) {
+            logWarning(params);
+        }
     };
     
     
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java
index eb66a476550b..9d95d2a694f8 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java
@@ -65,5 +65,9 @@ protected StatusDisplayer.Message showStatusMessage(ShowStatusMessageParams msg)
         }
         return null;
     }
-    
+
+    @Override
+    protected void showHtmlPage(HtmlPageParams msg) {
+        client.showHtmlPage(msg);
+    }
 }
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java
new file mode 100644
index 000000000000..91f6a2d1cfee
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.ui;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.util.concurrent.Callable;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.modules.java.lsp.server.htmlui.Browser;
+import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams;
+import org.netbeans.spi.htmlui.HtmlViewer;
+import org.openide.util.Exceptions;
+
+public class AbstractLspHtmlViewer implements HtmlViewer {
+    protected AbstractLspHtmlViewer() {
+    }
+
+    @Override
+    public View newView() {
+        return new View();
+    }
+
+    @Override
+    public void makeVisible(View view, Runnable whenReady) {
+        whenReady.run();
+    }
+
+    @Override
+    public void load(View view, ClassLoader loader, URL pageUrl, Callable initialize, String[] techIds) {
+        UIContext ui = UIContext.find();
+
+        Browser.Config c = new Browser.Config();
+        Fn.Presenter b = new Browser(c) {
+            @Override
+            protected void show(URI page) throws IOException {
+                try {
+                    ui.showHtmlPage(new HtmlPageParams(page.toASCIIString()));
+                } catch (Exception ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
+        };
+        b.displayPage(pageUrl, () -> {
+            try {
+//                ui.showStatusMessage(new ShowStatusMessageParams(MessageType.Error, "http://localhost:" + port));
+                Object v = initialize.call();
+                System.err.println("v: " + v);
+            } catch (Exception ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        });
+    }
+
+
+    public static final class View {
+        public View() {
+        }
+    }
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspStatusDisplayer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspStatusDisplayer.java
index 57cd695cf477..44be735f5618 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspStatusDisplayer.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspStatusDisplayer.java
@@ -19,7 +19,6 @@
 package org.netbeans.modules.java.lsp.server.ui;
 
 import javax.swing.event.ChangeListener;
-import org.eclipse.lsp4j.MessageParams;
 import org.eclipse.lsp4j.MessageType;
 import org.netbeans.modules.java.lsp.server.protocol.ShowStatusMessageParams;
 import org.openide.awt.StatusDisplayer;
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java
index d820f4e9538e..59a65864f754 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java
@@ -23,8 +23,10 @@
 import java.util.concurrent.CompletableFuture;
 import org.eclipse.lsp4j.MessageActionItem;
 import org.eclipse.lsp4j.MessageParams;
+import org.eclipse.lsp4j.MessageType;
 import org.eclipse.lsp4j.ShowMessageRequestParams;
 import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams;
 import org.netbeans.modules.java.lsp.server.protocol.ShowStatusMessageParams;
 import org.openide.awt.StatusDisplayer.Message;
 import org.openide.util.Lookup;
@@ -76,6 +78,9 @@ public static synchronized UIContext find() {
 
     protected abstract boolean isValid();
     protected abstract void showMessage(MessageParams msg);
+    protected void showHtmlPage(HtmlPageParams msg) {
+        showMessage(new MessageParams(MessageType.Log, msg.getUri()));
+    }
     protected abstract CompletableFuture showMessageRequest(ShowMessageRequestParams msg);
     protected abstract void logMessage(MessageParams msg);
     protected abstract Message showStatusMessage(ShowStatusMessageParams msg);
@@ -114,5 +119,10 @@ protected Message showStatusMessage(ShowStatusMessageParams msg) {
         protected boolean isValid() {
             return true;
         }
+
+        @Override
+        protected void showHtmlPage(HtmlPageParams msg) {
+            System.out.println("Open in browser: " + msg.getUri());
+        }
     }
 }
diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java
new file mode 100644
index 000000000000..9166d2a1869b
--- /dev/null
+++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import org.eclipse.lsp4j.MessageActionItem;
+import org.eclipse.lsp4j.MessageParams;
+import org.eclipse.lsp4j.PublishDiagnosticsParams;
+import org.eclipse.lsp4j.ShowMessageRequestParams;
+import org.netbeans.modules.java.lsp.server.protocol.DecorationRenderOptions;
+import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams;
+import org.netbeans.modules.java.lsp.server.protocol.NbCodeClientCapabilities;
+import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient;
+import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem;
+import org.netbeans.modules.java.lsp.server.protocol.SetTextEditorDecorationParams;
+import org.netbeans.modules.java.lsp.server.protocol.ShowInputBoxParams;
+import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams;
+import org.netbeans.modules.java.lsp.server.protocol.ShowStatusMessageParams;
+import org.netbeans.modules.java.lsp.server.protocol.TestProgressParams;
+
+public abstract class TestCodeLanguageClient implements NbCodeLanguageClient {
+    @Override
+    public void showStatusBarMessage(ShowStatusMessageParams params) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void showHtmlPage(HtmlPageParams params) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CompletableFuture> showQuickPick(ShowQuickPickParams params) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CompletableFuture showInputBox(ShowInputBoxParams params) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void notifyTestProgress(TestProgressParams params) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CompletableFuture createTextEditorDecoration(DecorationRenderOptions params) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void disposeTextEditorDecoration(String params) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public NbCodeClientCapabilities getNbCodeCapabilities() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void telemetryEvent(Object arg0) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void publishDiagnostics(PublishDiagnosticsParams arg0) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void showMessage(MessageParams arg0) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CompletableFuture showMessageRequest(ShowMessageRequestParams arg0) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void logMessage(MessageParams arg0) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
index 1265b97b444e..5cfd8ac0155c 100644
--- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
+++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
@@ -38,6 +38,7 @@
 import org.netbeans.modules.gsf.testrunner.api.TestSession;
 import org.netbeans.modules.gsf.testrunner.api.Testcase;
 import org.netbeans.modules.gsf.testrunner.api.Trouble;
+import org.netbeans.modules.java.lsp.server.TestCodeLanguageClient;
 import org.netbeans.modules.java.lsp.server.protocol.DecorationRenderOptions;
 import org.netbeans.modules.java.lsp.server.protocol.NbCodeClientCapabilities;
 import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient;
@@ -140,7 +141,7 @@ public FileObject find(String filename) {
         assertNotNull(testCase.getStackTrace());
     }
 
-    private static final class MockLanguageClient implements NbCodeLanguageClient {
+    private static final class MockLanguageClient extends TestCodeLanguageClient {
         private final List messages;
 
         MockLanguageClient(List messages) {
diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
index 5b9e704a4da9..e75a2af50985 100644
--- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
+++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
@@ -18,6 +18,7 @@
  */
 package org.netbeans.modules.java.lsp.server.protocol;
 
+import org.netbeans.modules.java.lsp.server.TestCodeLanguageClient;
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
@@ -148,7 +149,6 @@
 import org.netbeans.modules.java.source.BootClassPathUtil;
 import org.netbeans.modules.parsing.impl.indexing.implspi.CacheFolderProvider;
 import org.netbeans.spi.java.classpath.ClassPathProvider;
-import org.netbeans.spi.java.classpath.PathResourceImplementation;
 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
 import org.netbeans.spi.java.queries.AnnotationProcessingQueryImplementation;
 import org.netbeans.spi.lsp.ErrorProvider;
@@ -174,6 +174,7 @@
  *
  * @author lahvac
  */
+@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
 public class ServerTest extends NbTestCase {
 
     private final Gson gson = new Gson();
@@ -1551,7 +1552,7 @@ public void testFixImports() throws Exception {
         }
         List[] diags = new List[1];
         CountDownLatch indexingComplete = new CountDownLatch(1);
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void notifyProgress(ProgressParams params) {
             }
@@ -2913,7 +2914,7 @@ public void testCodeActionGenerateConstructor() throws Exception {
             w.write(code);
         }
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -3127,7 +3128,7 @@ public void testSourceActionConstructor() throws Exception {
             w.write(code);
         }
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -3258,7 +3259,7 @@ public void testSourceActionEqualsHashCode() throws Exception {
             w.write(code);
         }
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -3390,7 +3391,7 @@ public void testSourceActionToString() throws Exception {
             w.write(code);
         }
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -3509,7 +3510,7 @@ public void testSourceActionDelegateMethod() throws Exception {
             w.write(code);
         }
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -3633,7 +3634,7 @@ public void testSourceActionOverrideMethod() throws Exception {
             w.write(code);
         }
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -3754,7 +3755,7 @@ public void testSourceActionLogger() throws Exception {
             w.write(code);
         }
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -4018,7 +4019,7 @@ public void testMoveClass() throws Exception {
         List[] diags = new List[1];
         CountDownLatch indexingComplete = new CountDownLatch(1);
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -4178,7 +4179,7 @@ public void testMoveMethod() throws Exception {
         List[] diags = new List[1];
         CountDownLatch indexingComplete = new CountDownLatch(1);
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -4327,7 +4328,7 @@ public void testExtractInterface() throws Exception {
         List[] diags = new List[1];
         CountDownLatch indexingComplete = new CountDownLatch(1);
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -4492,7 +4493,7 @@ public void testExtractSuperclass() throws Exception {
         List[] diags = new List[1];
         CountDownLatch indexingComplete = new CountDownLatch(1);
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -4674,7 +4675,7 @@ public void testPullUp() throws Exception {
         List[] diags = new List[1];
         CountDownLatch indexingComplete = new CountDownLatch(1);
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -4751,7 +4752,12 @@ public CompletableFuture> showQuickPick(ShowQuickPickParams
 
             @Override
             public void showStatusBarMessage(ShowStatusMessageParams params) {
-                throw new UnsupportedOperationException("Not supported yet.");
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public void showHtmlPage(HtmlPageParams params) {
+                throw new UnsupportedOperationException();
             }
         }, client.getInputStream(), client.getOutputStream());
         serverLauncher.startListening();
@@ -4817,7 +4823,7 @@ public void testPushDown() throws Exception {
         List[] diags = new List[1];
         CountDownLatch indexingComplete = new CountDownLatch(1);
         WorkspaceEdit[] edit = new WorkspaceEdit[1];
-        Launcher serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() {
+        Launcher serverLauncher = LSPLauncher.createClientLauncher(new TestCodeLanguageClient() {
             @Override
             public void telemetryEvent(Object arg0) {
                 throw new UnsupportedOperationException("Not supported yet.");
@@ -4894,7 +4900,12 @@ public CompletableFuture> showQuickPick(ShowQuickPickParams
 
             @Override
             public void showStatusBarMessage(ShowStatusMessageParams params) {
-                throw new UnsupportedOperationException("Not supported yet.");
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public void showHtmlPage(HtmlPageParams params) {
+                throw new UnsupportedOperationException();
             }
         }, client.getInputStream(), client.getOutputStream());
         serverLauncher.startListening();
diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/AbstractDialogDisplayerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/AbstractDialogDisplayerTest.java
index 9d9ec81ebf0f..0d01594fd47e 100644
--- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/AbstractDialogDisplayerTest.java
+++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/AbstractDialogDisplayerTest.java
@@ -28,6 +28,7 @@
 import org.eclipse.lsp4j.MessageType;
 import org.eclipse.lsp4j.ShowMessageRequestParams;
 import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams;
 import org.netbeans.modules.java.lsp.server.protocol.ShowStatusMessageParams;
 import org.openide.NotifyDescriptor;
 import org.openide.awt.StatusDisplayer;
diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts
index 706d66b05f3c..3c52c64093c2 100644
--- a/java/java.lsp.server/vscode/src/extension.ts
+++ b/java/java.lsp.server/vscode/src/extension.ts
@@ -44,7 +44,7 @@ import { TestAdapterRegistrar } from 'vscode-test-adapter-util';
 import * as launcher from './nbcode';
 import {NbTestAdapter} from './testAdapter';
 import { StatusMessageRequest, ShowStatusMessageParams, QuickPickRequest, InputBoxRequest, TestProgressNotification, DebugConnector,
-         TextEditorDecorationCreateRequest, TextEditorDecorationSetNotification, TextEditorDecorationDisposeNotification,
+         TextEditorDecorationCreateRequest, TextEditorDecorationSetNotification, TextEditorDecorationDisposeNotification, HtmlPageRequest, HtmlPageParams,
 } from './protocol';
 import * as launchConfigurations from './launchConfigurations';
 
@@ -580,6 +580,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex
         c.start();
         c.onReady().then(() => {
             c.onNotification(StatusMessageRequest.type, showStatusBarMessage);
+            c.onNotification(HtmlPageRequest.type, showHtmlPage);
             c.onNotification(LogMessageNotification.type, (param) => handleLog(log, param.message));
             c.onRequest(QuickPickRequest.type, async param => {
                 const selected = await window.showQuickPick(param.items, { placeHolder: param.placeHolder, canPickMany: param.canPickMany });
@@ -632,6 +633,39 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex
         window.showErrorMessage('Error initializing ' + reason);
     });
 
+    function showHtmlPage(params : HtmlPageParams) {
+        function showUri(url: string, id: string, name: string) {
+            let uri = vscode.Uri.parse(url);
+            var http = require('http');
+
+            let host = uri.authority.split(":")[0];
+            let port = uri.authority.split(":")[1];
+
+            var options = {
+                host: host,
+                port: port,
+                path: uri.path
+            }
+            var request = http.request(options, function(res: any) {
+                var data = '';
+                res.on('data', function(chunk: any) {
+                    data += chunk;
+                });
+                res.on('end', function() {
+                    let view = vscode.window.createWebviewPanel(id, name, vscode.ViewColumn.One, {
+                        enableScripts: true,
+                    });
+                    view.webview.html = data;
+                });
+            });
+            request.on('error', function(e: any) {
+                vscode.window.showWarningMessage(e.message);
+            });
+            request.end();
+        }
+        showUri(params.uri, "test", "Showing a view");
+    }
+
     function showStatusBarMessage(params : ShowStatusMessageParams) {
         let decorated : string = params.message;
         let defTimeout;
diff --git a/java/java.lsp.server/vscode/src/protocol.ts b/java/java.lsp.server/vscode/src/protocol.ts
index 3c3a254637db..71b0b5218e79 100644
--- a/java/java.lsp.server/vscode/src/protocol.ts
+++ b/java/java.lsp.server/vscode/src/protocol.ts
@@ -37,6 +37,14 @@ export interface ShowStatusMessageParams extends ShowMessageParams {
     timeout?: number;
 }
 
+export interface HtmlPageParams {
+    uri: string;
+}
+
+export namespace HtmlPageRequest {
+    export const type = new NotificationType('window/showHtmlPage');
+};
+
 export namespace StatusMessageRequest {
     export const type = new NotificationType('window/showStatusBarMessage');
 };

From 9401affed196687916922f043af4e3c72be08f00 Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach 
Date: Mon, 20 Sep 2021 15:45:26 +0200
Subject: [PATCH 06/38] Java: Demo HTML UI

---
 .../lsp/server/htmlui/demo/HelloWorld.html    | 22 +++++
 .../server/htmlui/demo/HelloWorldCntrl.java   | 86 +++++++++++++++++++
 .../java/lsp/server/protocol/Server.java      |  2 +
 .../server/protocol/WorkspaceServiceImpl.java |  8 ++
 java/java.lsp.server/vscode/package-lock.json |  2 +-
 java/java.lsp.server/vscode/package.json      |  9 +-
 java/java.lsp.server/vscode/src/extension.ts  |  3 +
 7 files changed, 129 insertions(+), 3 deletions(-)
 create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html
 create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java

diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html
new file mode 100644
index 000000000000..a0cfc1f4a46e
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html
@@ -0,0 +1,22 @@
+
+    
+        HelloWorld
+        
+        
+    
+    
+        

VSNetBeans WebView Demo

+ + +

Your name has 0 characters

+
+ + +
+
+ + +
+

.

+ + \ No newline at end of file diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java new file mode 100644 index 000000000000..e7893e03a843 --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.java.lsp.server.htmlui.demo; + +import net.java.html.json.Model; +import net.java.html.json.Function; +import net.java.html.json.Property; +import net.java.html.json.ComputedProperty; +import net.java.html.json.OnPropertyChange; +import org.netbeans.api.htmlui.OpenHTMLRegistration; +import org.openide.util.NbBundle; +import org.openide.awt.ActionID; + +@Model(className = "HelloWorld", targetId = "", properties = { + @Property(name = "text", type = String.class), + @Property(name = "upper", type = boolean.class), + @Property(name = "update", type = boolean.class), + @Property(name = "helloMessage", type = String.class) +}) +public final class HelloWorldCntrl { + @ComputedProperty + static int count(String text) { + return text == null ? 0 : text.length(); + } + + @ComputedProperty + static boolean canSayHello(String text, boolean update) { + return text != null && !text.isEmpty() && !update; + } + + @ComputedProperty + static boolean displaySayHello(String text, boolean update) { + return !update; + } + + @Function + static void sayHello(HelloWorld model) { + updateHelloMessage(model); + model.setText(""); + } + + private static void updateHelloMessage(HelloWorld model) { + String name = model.getText(); + if (model.isUpper()) { + name = name.toUpperCase(); + } + model.setHelloMessage("Hello " + name + "!"); + } + + @OnPropertyChange({ "text", "update", "upper" }) + static void updateImmediately(HelloWorld model) { + if (model.isUpdate()) { + updateHelloMessage(model); + } + } + + @ActionID( + category = "Tools", + id = "org.netbeans.modules.java.lsp.server.protocol.HelloWorld" + ) + @NbBundle.Messages("CTL_HelloWorld=Open HTML Hello World!") + @OpenHTMLRegistration( + url = "HelloWorld.html", + displayName = "#CTL_HelloWorld" + //, iconBase="SET/PATH/TO/ICON/HERE" + ) + public static HelloWorld onPageLoad() { + return new HelloWorld().applyBindings(); + } +} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java index fbce8d608cef..ed6beb64e8c9 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java @@ -632,6 +632,7 @@ private InitializeResult constructInitResponse(JavaSource src) { JAVA_LOAD_WORKSPACE_TESTS, JAVA_NEW_FROM_TEMPLATE, JAVA_NEW_PROJECT, + JAVA_HTML_DEMO, JAVA_PROJECT_CONFIGURATION_COMPLETION, JAVA_SUPER_IMPLEMENTATION, NATIVE_IMAGE_FIND_DEBUG_PROCESS_TO_ATTACH)); @@ -749,6 +750,7 @@ protected LanguageClient client() { public static final String JAVA_BUILD_WORKSPACE = "java.build.workspace"; public static final String JAVA_NEW_FROM_TEMPLATE = "java.new.from.template"; public static final String JAVA_NEW_PROJECT = "java.new.project"; + public static final String JAVA_HTML_DEMO = "java.html.demo"; public static final String JAVA_GET_PROJECT_SOURCE_ROOTS = "java.get.project.source.roots"; public static final String JAVA_GET_PROJECT_CLASSPATH = "java.get.project.classpath"; public static final String JAVA_GET_PROJECT_PACKAGES = "java.get.project.packages"; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java index 0d65a1fddd54..378bf90c1a93 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java @@ -23,6 +23,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.sun.source.util.TreePath; +import java.awt.event.ActionEvent; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -47,6 +48,7 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; +import javax.swing.Action; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.DidChangeWatchedFilesParams; @@ -94,6 +96,7 @@ import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.ProjectConfiguration; import org.netbeans.spi.project.ProjectConfigurationProvider; +import org.openide.awt.Actions; import org.openide.filesystems.FileObject; import org.openide.filesystems.URLMapper; import org.openide.util.Exceptions; @@ -130,6 +133,11 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { return LspTemplateUI.createFromTemplate("Templates", client, params); case Server.JAVA_NEW_PROJECT: return LspTemplateUI.createProject("Templates/Project", client, params); + case Server.JAVA_HTML_DEMO: { + Action action = Actions.forID("Tools","org.netbeans.modules.java.lsp.server.protocol.HelloWorld"); + action.actionPerformed(new ActionEvent(this, 0, "")); + break; + } case Server.JAVA_BUILD_WORKSPACE: { final CommandProgress progressOfCompilation = new CommandProgress(); final Lookup ctx = Lookups.singleton(progressOfCompilation); diff --git a/java/java.lsp.server/vscode/package-lock.json b/java/java.lsp.server/vscode/package-lock.json index 33e724a4bb29..66d8e63f22ab 100644 --- a/java/java.lsp.server/vscode/package-lock.json +++ b/java/java.lsp.server/vscode/package-lock.json @@ -1,6 +1,6 @@ { "name": "apache-netbeans-java", - "version": "12.4.0", + "version": "0.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/java/java.lsp.server/vscode/package.json b/java/java.lsp.server/vscode/package.json index 418692271c3a..00ec5ee08f50 100644 --- a/java/java.lsp.server/vscode/package.json +++ b/java/java.lsp.server/vscode/package.json @@ -4,7 +4,7 @@ "description": "Apache NetBeans Language Server Extension for Visual Studio Code", "author": "Apache NetBeans", "license": "Apache 2.0", - "version": "12.4.0", + "version": "0.1.0", "preview": true, "repository": { "type": "git", @@ -298,6 +298,11 @@ } ], "commands": [ + { + "command": "java.workspace.html.demo", + "title": "Demo HTML UI", + "category": "Java" + }, { "command": "java.workspace.compile", "title": "Compile Workspace", @@ -389,7 +394,7 @@ "nbcode": "node ./out/nbcode.js", "nbjavac": "node ./out/nbcode.js -J-Dnetbeans.close=true --modules --install .*nbjavac.*", "apisupport": "node ./out/nbcode.js -J-Dnetbeans.close=true --modules --install '(org.netbeans.libs.xerces|org.netbeans.modules.editor.structure|org.netbeans.modules.xml|org.netbeans.modules.xml.axi|org.netbeans.modules.xml.retriever|org.netbeans.modules.xml.schema.model|org.netbeans.modules.xml.tax|org.netbeans.modules.xml.text|org.netbeans.modules.ant.browsetask|.*apisupport.*|org.netbeans.modules.debugger.jpda.ant)' && node ./out/nbcode.js -J-Dnetbeans.close=true --modules --enable .*apisupport.ant" - }, + }, "devDependencies": { "@types/glob": "^7.1.1", "@types/mocha": "^7.0.2", diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index 3c52c64093c2..099ba92a18ee 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -241,6 +241,9 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { throw `Client ${c} doesn't support new project`; } })); + context.subscriptions.push(commands.registerCommand('java.workspace.html.demo', () => { + vscode.commands.executeCommand('java.html.demo'); + })); context.subscriptions.push(commands.registerCommand('java.workspace.compile', () => { return window.withProgress({ location: ProgressLocation.Window }, p => { return new Promise(async (resolve, reject) => { From 0109977044c5fddedb5387ec52b772136d9cd454 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 20 Sep 2021 16:43:54 +0200 Subject: [PATCH 07/38] Command java.html.demo is supported --- .../modules/java/lsp/server/protocol/WorkspaceServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java index 378bf90c1a93..f96c550029db 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java @@ -136,7 +136,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { case Server.JAVA_HTML_DEMO: { Action action = Actions.forID("Tools","org.netbeans.modules.java.lsp.server.protocol.HelloWorld"); action.actionPerformed(new ActionEvent(this, 0, "")); - break; + return CompletableFuture.completedFuture(true); } case Server.JAVA_BUILD_WORKSPACE: { final CommandProgress progressOfCompilation = new CommandProgress(); From 0cfa785cf9c677c44f195ffab1c399c96d84bc7e Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 20 Sep 2021 17:36:35 +0200 Subject: [PATCH 08/38] Demo of refactoring UI --- .../lsp/server/htmlui/demo/HelloWorld.css | 108 ++++ .../lsp/server/htmlui/demo/HelloWorld.html | 72 ++- .../server/htmlui/demo/HelloWorldCntrl.java | 110 ++-- .../java/lsp/server/htmlui/demo/codicon.css | 485 ++++++++++++++++++ .../java/lsp/server/htmlui/demo/codicon.ttf | Bin 0 -> 65608 bytes java/java.lsp.server/vscode/src/extension.ts | 12 +- 6 files changed, 737 insertions(+), 50 deletions(-) create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.css create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.css create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.ttf diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.css b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.css new file mode 100644 index 000000000000..29475004deb7 --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.css @@ -0,0 +1,108 @@ +html, body { + height: 100%; + padding: 0; + margin: 0; +} +body { + display: flex; + flex-direction: column; + overflow-x: scroll; +} +input, select { + width: 100%; + font-family: var(--vscode-editor-font-family) !important; + border: var(--vscode-input-border); + margin-right: 6px !important; + background: var(--vscode-input-background); + color: var(--vscode-input-foreground); + box-sizing: border-box; +} +input:focus, select:focus { + outline-color: var(--vscode-focusBorder); +} +input { + padding: 5px 4px !important; +} +select { + padding: 4px !important; +} +button { + font-size: 13px; + text-decoration: none; + border: none; + background: var(--vscode-button-background); + color: var(--vscode-button-foreground); + font-family: var(--vscode-font-family) !important; + padding: 4px 10px 4px 10px; + margin: 5px; + cursor: pointer; +} +button:hover, button:focus { + background: var(--vscode-button-hoverBackground); +} +button:focus { + outline: 1px solid var(--vscode-button-hoverBackground); + outline-offset: 2px; +} +label { + display: block; + margin-bottom: 5px; +} +.caption1 { + margin-bottom: -20px !important; +} +.caption2 { + margin-bottom: -20px !important; + margin-left: -32px; +} +.action { + border-radius: 4px; + padding: 2px; + margin: 3px 0px; +} +.action:hover { + background-color: var(--vscode-list-inactiveSelectionBackground); +} +.preview-panel { + margin: 0px; + padding: 10px; + font-family: var(--vscode-editor-font-family) !important; + background-color: var(--vscode-sideBar-background); + cursor: default; +} +.section { + padding: 20px 20px 0px; +} +.section1 { + padding: 0px 10px; +} +.section2 { + padding: 0px 10px; + margin-top: -6px; +} +.vdivider { + margin-bottom: 20px; +} +.hdivider { + margin-left: 6px; +} +.row { + padding: 3px 10px; +} +.row:hover { + background-color: var(--vscode-list-hoverBackground); +} +.flex { + display: flex; +} +.flex-grow { + flex-grow: 1; + display: block; +} +.flex-vscrollable { + overflow-x: hidden; + overflow-y: auto; +} +.align-right { + margin-left: auto; +} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html index a0cfc1f4a46e..e1d0dc8c6725 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html @@ -1,22 +1,54 @@ - - - HelloWorld - - - - -

VSNetBeans WebView Demo

- - -

Your name has 0 characters

-
- - + + + + + + + + Refactor: Change Signature + + + +
+
+
+ + +
+
+ + +
+
+ + +
-
- - + +
+ + +
-

.

- - \ No newline at end of file +
+
+
+ + + + + +
+
+
+ +
+
+

.

+
+
+ + +
+ + diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java index e7893e03a843..1389537e15fd 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java @@ -18,56 +18,91 @@ */ package org.netbeans.modules.java.lsp.server.htmlui.demo; +import java.util.Arrays; +import java.util.List; import net.java.html.json.Model; -import net.java.html.json.Function; import net.java.html.json.Property; import net.java.html.json.ComputedProperty; -import net.java.html.json.OnPropertyChange; +import net.java.html.json.Function; +import net.java.html.json.ModelOperation; import org.netbeans.api.htmlui.OpenHTMLRegistration; import org.openide.util.NbBundle; import org.openide.awt.ActionID; +import org.openide.awt.StatusDisplayer; -@Model(className = "HelloWorld", targetId = "", properties = { - @Property(name = "text", type = String.class), - @Property(name = "upper", type = boolean.class), - @Property(name = "update", type = boolean.class), - @Property(name = "helloMessage", type = String.class) +@Model(className = "HelloWorld", targetId = "", instance = true, builder = "with", properties = { + @Property(name = "selectedModifier", type = String.class), + @Property(name = "name", type = String.class), + @Property(name = "returnType", type = String.class), + @Property(name = "parameters", type = Parameter.class, array = true) }) public final class HelloWorldCntrl { - @ComputedProperty - static int count(String text) { - return text == null ? 0 : text.length(); + @Model(className = "Parameter", properties = { + @Property(name = "type", type = String.class), + @Property(name = "name", type = String.class) + }) + static class ParameterCntrl { } - @ComputedProperty - static boolean canSayHello(String text, boolean update) { - return text != null && !text.isEmpty() && !update; + private RefactoringData data; + + @ModelOperation + void assignData(HelloWorld model, RefactoringData data) { + this.data = data; } - @ComputedProperty - static boolean displaySayHello(String text, boolean update) { - return !update; + @Function + void doRefactoring(HelloWorld model) { + StatusDisplayer.getDefault().setStatusText("use data: " + data + " and model " + model); } @Function - static void sayHello(HelloWorld model) { - updateHelloMessage(model); - model.setText(""); + void moveUpParameter(HelloWorld model, Parameter data) { + final List arr = model.getParameters(); + int index = arr.indexOf(data); + if (index > 0) { + Parameter other = arr.get(index - 1); + arr.set(index, other); + arr.set(index - 1, data); + } } - private static void updateHelloMessage(HelloWorld model) { - String name = model.getText(); - if (model.isUpper()) { - name = name.toUpperCase(); + @Function + void moveDownParameter(HelloWorld model, Parameter data) { + final List arr = model.getParameters(); + int index = arr.indexOf(data); + if (index != -1 && index + 1 < arr.size()) { + Parameter other = arr.get(index + 1); + arr.set(index, other); + arr.set(index + 1, data); } - model.setHelloMessage("Hello " + name + "!"); } - @OnPropertyChange({ "text", "update", "upper" }) - static void updateImmediately(HelloWorld model) { - if (model.isUpdate()) { - updateHelloMessage(model); + @Function + void removeParameter(HelloWorld model, Parameter data) { + model.getParameters().remove(data); + } + + @ComputedProperty + static List availableModifiers() { + return Arrays.asList("public", "protected", "package-package", "private"); + } + + @ComputedProperty + static String preview( + String selectedModifier, String returnType, String name, List parameters + ) { + StringBuilder sb = new StringBuilder(); + sb.append(selectedModifier).append(" ").append(returnType); + sb.append(" ").append(name).append("("); + String sep = ""; + for (Parameter p : parameters) { + sb.append(sep); + sb.append(p.getType()).append(" ").append(p.getName()); + sep = ", "; } + sb.append(")"); + return sb.toString(); } @ActionID( @@ -81,6 +116,23 @@ static void updateImmediately(HelloWorld model) { //, iconBase="SET/PATH/TO/ICON/HERE" ) public static HelloWorld onPageLoad() { - return new HelloWorld().applyBindings(); + final HelloWorld model = new HelloWorld(); + model. + withName("openSource"). + withReturnType("boolean"). + withSelectedModifier("public"). + withParameters( + new Parameter("Lookup.Provider", "project"), + new Parameter("String", "className"), + new Parameter("String", "methodName"), + new Parameter("String", "signature"), + new Parameter("int", "line") + ). + assignData(new RefactoringData()); + + return model.applyBindings(); + } + + static final class RefactoringData { } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.css b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.css new file mode 100644 index 000000000000..c2771b5e881e --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.css @@ -0,0 +1,485 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +@font-face { + font-family: "codicon"; + src: url("./codicon.ttf?9642aa1d48ab4e55aa1bf3f0b8678aa1") format("truetype"); +} + +.codicon[class*='codicon-'] { + font: normal normal normal 16px/1 codicon; + display: inline-block; + text-decoration: none; + text-rendering: auto; + text-align: center; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + user-select: none; + -webkit-user-select: none; + -ms-user-select: none; +} + + +.codicon-add:before { content: "\ea60" } +.codicon-plus:before { content: "\ea60" } +.codicon-gist-new:before { content: "\ea60" } +.codicon-repo-create:before { content: "\ea60" } +.codicon-lightbulb:before { content: "\ea61" } +.codicon-light-bulb:before { content: "\ea61" } +.codicon-repo:before { content: "\ea62" } +.codicon-repo-delete:before { content: "\ea62" } +.codicon-gist-fork:before { content: "\ea63" } +.codicon-repo-forked:before { content: "\ea63" } +.codicon-git-pull-request:before { content: "\ea64" } +.codicon-git-pull-request-abandoned:before { content: "\ea64" } +.codicon-record-keys:before { content: "\ea65" } +.codicon-keyboard:before { content: "\ea65" } +.codicon-tag:before { content: "\ea66" } +.codicon-tag-add:before { content: "\ea66" } +.codicon-tag-remove:before { content: "\ea66" } +.codicon-person:before { content: "\ea67" } +.codicon-person-follow:before { content: "\ea67" } +.codicon-person-outline:before { content: "\ea67" } +.codicon-person-filled:before { content: "\ea67" } +.codicon-git-branch:before { content: "\ea68" } +.codicon-git-branch-create:before { content: "\ea68" } +.codicon-git-branch-delete:before { content: "\ea68" } +.codicon-source-control:before { content: "\ea68" } +.codicon-mirror:before { content: "\ea69" } +.codicon-mirror-public:before { content: "\ea69" } +.codicon-star:before { content: "\ea6a" } +.codicon-star-add:before { content: "\ea6a" } +.codicon-star-delete:before { content: "\ea6a" } +.codicon-star-empty:before { content: "\ea6a" } +.codicon-comment:before { content: "\ea6b" } +.codicon-comment-add:before { content: "\ea6b" } +.codicon-alert:before { content: "\ea6c" } +.codicon-warning:before { content: "\ea6c" } +.codicon-search:before { content: "\ea6d" } +.codicon-search-save:before { content: "\ea6d" } +.codicon-log-out:before { content: "\ea6e" } +.codicon-sign-out:before { content: "\ea6e" } +.codicon-log-in:before { content: "\ea6f" } +.codicon-sign-in:before { content: "\ea6f" } +.codicon-eye:before { content: "\ea70" } +.codicon-eye-unwatch:before { content: "\ea70" } +.codicon-eye-watch:before { content: "\ea70" } +.codicon-circle-filled:before { content: "\ea71" } +.codicon-primitive-dot:before { content: "\ea71" } +.codicon-close-dirty:before { content: "\ea71" } +.codicon-debug-breakpoint:before { content: "\ea71" } +.codicon-debug-breakpoint-disabled:before { content: "\ea71" } +.codicon-debug-hint:before { content: "\ea71" } +.codicon-primitive-square:before { content: "\ea72" } +.codicon-edit:before { content: "\ea73" } +.codicon-pencil:before { content: "\ea73" } +.codicon-info:before { content: "\ea74" } +.codicon-issue-opened:before { content: "\ea74" } +.codicon-gist-private:before { content: "\ea75" } +.codicon-git-fork-private:before { content: "\ea75" } +.codicon-lock:before { content: "\ea75" } +.codicon-mirror-private:before { content: "\ea75" } +.codicon-close:before { content: "\ea76" } +.codicon-remove-close:before { content: "\ea76" } +.codicon-x:before { content: "\ea76" } +.codicon-repo-sync:before { content: "\ea77" } +.codicon-sync:before { content: "\ea77" } +.codicon-clone:before { content: "\ea78" } +.codicon-desktop-download:before { content: "\ea78" } +.codicon-beaker:before { content: "\ea79" } +.codicon-microscope:before { content: "\ea79" } +.codicon-vm:before { content: "\ea7a" } +.codicon-device-desktop:before { content: "\ea7a" } +.codicon-file:before { content: "\ea7b" } +.codicon-file-text:before { content: "\ea7b" } +.codicon-more:before { content: "\ea7c" } +.codicon-ellipsis:before { content: "\ea7c" } +.codicon-kebab-horizontal:before { content: "\ea7c" } +.codicon-mail-reply:before { content: "\ea7d" } +.codicon-reply:before { content: "\ea7d" } +.codicon-organization:before { content: "\ea7e" } +.codicon-organization-filled:before { content: "\ea7e" } +.codicon-organization-outline:before { content: "\ea7e" } +.codicon-new-file:before { content: "\ea7f" } +.codicon-file-add:before { content: "\ea7f" } +.codicon-new-folder:before { content: "\ea80" } +.codicon-file-directory-create:before { content: "\ea80" } +.codicon-trash:before { content: "\ea81" } +.codicon-trashcan:before { content: "\ea81" } +.codicon-history:before { content: "\ea82" } +.codicon-clock:before { content: "\ea82" } +.codicon-folder:before { content: "\ea83" } +.codicon-file-directory:before { content: "\ea83" } +.codicon-symbol-folder:before { content: "\ea83" } +.codicon-logo-github:before { content: "\ea84" } +.codicon-mark-github:before { content: "\ea84" } +.codicon-github:before { content: "\ea84" } +.codicon-terminal:before { content: "\ea85" } +.codicon-console:before { content: "\ea85" } +.codicon-repl:before { content: "\ea85" } +.codicon-zap:before { content: "\ea86" } +.codicon-symbol-event:before { content: "\ea86" } +.codicon-error:before { content: "\ea87" } +.codicon-stop:before { content: "\ea87" } +.codicon-variable:before { content: "\ea88" } +.codicon-symbol-variable:before { content: "\ea88" } +.codicon-array:before { content: "\ea8a" } +.codicon-symbol-array:before { content: "\ea8a" } +.codicon-symbol-module:before { content: "\ea8b" } +.codicon-symbol-package:before { content: "\ea8b" } +.codicon-symbol-namespace:before { content: "\ea8b" } +.codicon-symbol-object:before { content: "\ea8b" } +.codicon-symbol-method:before { content: "\ea8c" } +.codicon-symbol-function:before { content: "\ea8c" } +.codicon-symbol-constructor:before { content: "\ea8c" } +.codicon-symbol-boolean:before { content: "\ea8f" } +.codicon-symbol-null:before { content: "\ea8f" } +.codicon-symbol-numeric:before { content: "\ea90" } +.codicon-symbol-number:before { content: "\ea90" } +.codicon-symbol-structure:before { content: "\ea91" } +.codicon-symbol-struct:before { content: "\ea91" } +.codicon-symbol-parameter:before { content: "\ea92" } +.codicon-symbol-type-parameter:before { content: "\ea92" } +.codicon-symbol-key:before { content: "\ea93" } +.codicon-symbol-text:before { content: "\ea93" } +.codicon-symbol-reference:before { content: "\ea94" } +.codicon-go-to-file:before { content: "\ea94" } +.codicon-symbol-enum:before { content: "\ea95" } +.codicon-symbol-value:before { content: "\ea95" } +.codicon-symbol-ruler:before { content: "\ea96" } +.codicon-symbol-unit:before { content: "\ea96" } +.codicon-activate-breakpoints:before { content: "\ea97" } +.codicon-archive:before { content: "\ea98" } +.codicon-arrow-both:before { content: "\ea99" } +.codicon-arrow-down:before { content: "\ea9a" } +.codicon-arrow-left:before { content: "\ea9b" } +.codicon-arrow-right:before { content: "\ea9c" } +.codicon-arrow-small-down:before { content: "\ea9d" } +.codicon-arrow-small-left:before { content: "\ea9e" } +.codicon-arrow-small-right:before { content: "\ea9f" } +.codicon-arrow-small-up:before { content: "\eaa0" } +.codicon-arrow-up:before { content: "\eaa1" } +.codicon-bell:before { content: "\eaa2" } +.codicon-bold:before { content: "\eaa3" } +.codicon-book:before { content: "\eaa4" } +.codicon-bookmark:before { content: "\eaa5" } +.codicon-debug-breakpoint-conditional-unverified:before { content: "\eaa6" } +.codicon-debug-breakpoint-conditional:before { content: "\eaa7" } +.codicon-debug-breakpoint-conditional-disabled:before { content: "\eaa7" } +.codicon-debug-breakpoint-data-unverified:before { content: "\eaa8" } +.codicon-debug-breakpoint-data:before { content: "\eaa9" } +.codicon-debug-breakpoint-data-disabled:before { content: "\eaa9" } +.codicon-debug-breakpoint-log-unverified:before { content: "\eaaa" } +.codicon-debug-breakpoint-log:before { content: "\eaab" } +.codicon-debug-breakpoint-log-disabled:before { content: "\eaab" } +.codicon-briefcase:before { content: "\eaac" } +.codicon-broadcast:before { content: "\eaad" } +.codicon-browser:before { content: "\eaae" } +.codicon-bug:before { content: "\eaaf" } +.codicon-calendar:before { content: "\eab0" } +.codicon-case-sensitive:before { content: "\eab1" } +.codicon-check:before { content: "\eab2" } +.codicon-checklist:before { content: "\eab3" } +.codicon-chevron-down:before { content: "\eab4" } +.codicon-chevron-left:before { content: "\eab5" } +.codicon-chevron-right:before { content: "\eab6" } +.codicon-chevron-up:before { content: "\eab7" } +.codicon-chrome-close:before { content: "\eab8" } +.codicon-chrome-maximize:before { content: "\eab9" } +.codicon-chrome-minimize:before { content: "\eaba" } +.codicon-chrome-restore:before { content: "\eabb" } +.codicon-circle-outline:before { content: "\eabc" } +.codicon-debug-breakpoint-unverified:before { content: "\eabc" } +.codicon-circle-slash:before { content: "\eabd" } +.codicon-circuit-board:before { content: "\eabe" } +.codicon-clear-all:before { content: "\eabf" } +.codicon-clippy:before { content: "\eac0" } +.codicon-close-all:before { content: "\eac1" } +.codicon-cloud-download:before { content: "\eac2" } +.codicon-cloud-upload:before { content: "\eac3" } +.codicon-code:before { content: "\eac4" } +.codicon-collapse-all:before { content: "\eac5" } +.codicon-color-mode:before { content: "\eac6" } +.codicon-comment-discussion:before { content: "\eac7" } +.codicon-credit-card:before { content: "\eac9" } +.codicon-dash:before { content: "\eacc" } +.codicon-dashboard:before { content: "\eacd" } +.codicon-database:before { content: "\eace" } +.codicon-debug-continue:before { content: "\eacf" } +.codicon-debug-disconnect:before { content: "\ead0" } +.codicon-debug-pause:before { content: "\ead1" } +.codicon-debug-restart:before { content: "\ead2" } +.codicon-debug-start:before { content: "\ead3" } +.codicon-debug-step-into:before { content: "\ead4" } +.codicon-debug-step-out:before { content: "\ead5" } +.codicon-debug-step-over:before { content: "\ead6" } +.codicon-debug-stop:before { content: "\ead7" } +.codicon-debug:before { content: "\ead8" } +.codicon-device-camera-video:before { content: "\ead9" } +.codicon-device-camera:before { content: "\eada" } +.codicon-device-mobile:before { content: "\eadb" } +.codicon-diff-added:before { content: "\eadc" } +.codicon-diff-ignored:before { content: "\eadd" } +.codicon-diff-modified:before { content: "\eade" } +.codicon-diff-removed:before { content: "\eadf" } +.codicon-diff-renamed:before { content: "\eae0" } +.codicon-diff:before { content: "\eae1" } +.codicon-discard:before { content: "\eae2" } +.codicon-editor-layout:before { content: "\eae3" } +.codicon-empty-window:before { content: "\eae4" } +.codicon-exclude:before { content: "\eae5" } +.codicon-extensions:before { content: "\eae6" } +.codicon-eye-closed:before { content: "\eae7" } +.codicon-file-binary:before { content: "\eae8" } +.codicon-file-code:before { content: "\eae9" } +.codicon-file-media:before { content: "\eaea" } +.codicon-file-pdf:before { content: "\eaeb" } +.codicon-file-submodule:before { content: "\eaec" } +.codicon-file-symlink-directory:before { content: "\eaed" } +.codicon-file-symlink-file:before { content: "\eaee" } +.codicon-file-zip:before { content: "\eaef" } +.codicon-files:before { content: "\eaf0" } +.codicon-filter:before { content: "\eaf1" } +.codicon-flame:before { content: "\eaf2" } +.codicon-fold-down:before { content: "\eaf3" } +.codicon-fold-up:before { content: "\eaf4" } +.codicon-fold:before { content: "\eaf5" } +.codicon-folder-active:before { content: "\eaf6" } +.codicon-folder-opened:before { content: "\eaf7" } +.codicon-gear:before { content: "\eaf8" } +.codicon-gift:before { content: "\eaf9" } +.codicon-gist-secret:before { content: "\eafa" } +.codicon-gist:before { content: "\eafb" } +.codicon-git-commit:before { content: "\eafc" } +.codicon-git-compare:before { content: "\eafd" } +.codicon-compare-changes:before { content: "\eafd" } +.codicon-git-merge:before { content: "\eafe" } +.codicon-github-action:before { content: "\eaff" } +.codicon-github-alt:before { content: "\eb00" } +.codicon-globe:before { content: "\eb01" } +.codicon-grabber:before { content: "\eb02" } +.codicon-graph:before { content: "\eb03" } +.codicon-gripper:before { content: "\eb04" } +.codicon-heart:before { content: "\eb05" } +.codicon-home:before { content: "\eb06" } +.codicon-horizontal-rule:before { content: "\eb07" } +.codicon-hubot:before { content: "\eb08" } +.codicon-inbox:before { content: "\eb09" } +.codicon-issue-reopened:before { content: "\eb0b" } +.codicon-issues:before { content: "\eb0c" } +.codicon-italic:before { content: "\eb0d" } +.codicon-jersey:before { content: "\eb0e" } +.codicon-json:before { content: "\eb0f" } +.codicon-kebab-vertical:before { content: "\eb10" } +.codicon-key:before { content: "\eb11" } +.codicon-law:before { content: "\eb12" } +.codicon-lightbulb-autofix:before { content: "\eb13" } +.codicon-link-external:before { content: "\eb14" } +.codicon-link:before { content: "\eb15" } +.codicon-list-ordered:before { content: "\eb16" } +.codicon-list-unordered:before { content: "\eb17" } +.codicon-live-share:before { content: "\eb18" } +.codicon-loading:before { content: "\eb19" } +.codicon-location:before { content: "\eb1a" } +.codicon-mail-read:before { content: "\eb1b" } +.codicon-mail:before { content: "\eb1c" } +.codicon-markdown:before { content: "\eb1d" } +.codicon-megaphone:before { content: "\eb1e" } +.codicon-mention:before { content: "\eb1f" } +.codicon-milestone:before { content: "\eb20" } +.codicon-mortar-board:before { content: "\eb21" } +.codicon-move:before { content: "\eb22" } +.codicon-multiple-windows:before { content: "\eb23" } +.codicon-mute:before { content: "\eb24" } +.codicon-no-newline:before { content: "\eb25" } +.codicon-note:before { content: "\eb26" } +.codicon-octoface:before { content: "\eb27" } +.codicon-open-preview:before { content: "\eb28" } +.codicon-package:before { content: "\eb29" } +.codicon-paintcan:before { content: "\eb2a" } +.codicon-pin:before { content: "\eb2b" } +.codicon-play:before { content: "\eb2c" } +.codicon-run:before { content: "\eb2c" } +.codicon-plug:before { content: "\eb2d" } +.codicon-preserve-case:before { content: "\eb2e" } +.codicon-preview:before { content: "\eb2f" } +.codicon-project:before { content: "\eb30" } +.codicon-pulse:before { content: "\eb31" } +.codicon-question:before { content: "\eb32" } +.codicon-quote:before { content: "\eb33" } +.codicon-radio-tower:before { content: "\eb34" } +.codicon-reactions:before { content: "\eb35" } +.codicon-references:before { content: "\eb36" } +.codicon-refresh:before { content: "\eb37" } +.codicon-regex:before { content: "\eb38" } +.codicon-remote-explorer:before { content: "\eb39" } +.codicon-remote:before { content: "\eb3a" } +.codicon-remove:before { content: "\eb3b" } +.codicon-replace-all:before { content: "\eb3c" } +.codicon-replace:before { content: "\eb3d" } +.codicon-repo-clone:before { content: "\eb3e" } +.codicon-repo-force-push:before { content: "\eb3f" } +.codicon-repo-pull:before { content: "\eb40" } +.codicon-repo-push:before { content: "\eb41" } +.codicon-report:before { content: "\eb42" } +.codicon-request-changes:before { content: "\eb43" } +.codicon-rocket:before { content: "\eb44" } +.codicon-root-folder-opened:before { content: "\eb45" } +.codicon-root-folder:before { content: "\eb46" } +.codicon-rss:before { content: "\eb47" } +.codicon-ruby:before { content: "\eb48" } +.codicon-save-all:before { content: "\eb49" } +.codicon-save-as:before { content: "\eb4a" } +.codicon-save:before { content: "\eb4b" } +.codicon-screen-full:before { content: "\eb4c" } +.codicon-screen-normal:before { content: "\eb4d" } +.codicon-search-stop:before { content: "\eb4e" } +.codicon-server:before { content: "\eb50" } +.codicon-settings-gear:before { content: "\eb51" } +.codicon-settings:before { content: "\eb52" } +.codicon-shield:before { content: "\eb53" } +.codicon-smiley:before { content: "\eb54" } +.codicon-sort-precedence:before { content: "\eb55" } +.codicon-split-horizontal:before { content: "\eb56" } +.codicon-split-vertical:before { content: "\eb57" } +.codicon-squirrel:before { content: "\eb58" } +.codicon-star-full:before { content: "\eb59" } +.codicon-star-half:before { content: "\eb5a" } +.codicon-symbol-class:before { content: "\eb5b" } +.codicon-symbol-color:before { content: "\eb5c" } +.codicon-symbol-constant:before { content: "\eb5d" } +.codicon-symbol-enum-member:before { content: "\eb5e" } +.codicon-symbol-field:before { content: "\eb5f" } +.codicon-symbol-file:before { content: "\eb60" } +.codicon-symbol-interface:before { content: "\eb61" } +.codicon-symbol-keyword:before { content: "\eb62" } +.codicon-symbol-misc:before { content: "\eb63" } +.codicon-symbol-operator:before { content: "\eb64" } +.codicon-symbol-property:before { content: "\eb65" } +.codicon-wrench:before { content: "\eb65" } +.codicon-wrench-subaction:before { content: "\eb65" } +.codicon-symbol-snippet:before { content: "\eb66" } +.codicon-tasklist:before { content: "\eb67" } +.codicon-telescope:before { content: "\eb68" } +.codicon-text-size:before { content: "\eb69" } +.codicon-three-bars:before { content: "\eb6a" } +.codicon-thumbsdown:before { content: "\eb6b" } +.codicon-thumbsup:before { content: "\eb6c" } +.codicon-tools:before { content: "\eb6d" } +.codicon-triangle-down:before { content: "\eb6e" } +.codicon-triangle-left:before { content: "\eb6f" } +.codicon-triangle-right:before { content: "\eb70" } +.codicon-triangle-up:before { content: "\eb71" } +.codicon-twitter:before { content: "\eb72" } +.codicon-unfold:before { content: "\eb73" } +.codicon-unlock:before { content: "\eb74" } +.codicon-unmute:before { content: "\eb75" } +.codicon-unverified:before { content: "\eb76" } +.codicon-verified:before { content: "\eb77" } +.codicon-versions:before { content: "\eb78" } +.codicon-vm-active:before { content: "\eb79" } +.codicon-vm-outline:before { content: "\eb7a" } +.codicon-vm-running:before { content: "\eb7b" } +.codicon-watch:before { content: "\eb7c" } +.codicon-whitespace:before { content: "\eb7d" } +.codicon-whole-word:before { content: "\eb7e" } +.codicon-window:before { content: "\eb7f" } +.codicon-word-wrap:before { content: "\eb80" } +.codicon-zoom-in:before { content: "\eb81" } +.codicon-zoom-out:before { content: "\eb82" } +.codicon-list-filter:before { content: "\eb83" } +.codicon-list-flat:before { content: "\eb84" } +.codicon-list-selection:before { content: "\eb85" } +.codicon-selection:before { content: "\eb85" } +.codicon-list-tree:before { content: "\eb86" } +.codicon-debug-breakpoint-function-unverified:before { content: "\eb87" } +.codicon-debug-breakpoint-function:before { content: "\eb88" } +.codicon-debug-breakpoint-function-disabled:before { content: "\eb88" } +.codicon-debug-stackframe-active:before { content: "\eb89" } +.codicon-debug-stackframe-dot:before { content: "\eb8a" } +.codicon-debug-stackframe:before { content: "\eb8b" } +.codicon-debug-stackframe-focused:before { content: "\eb8b" } +.codicon-debug-breakpoint-unsupported:before { content: "\eb8c" } +.codicon-symbol-string:before { content: "\eb8d" } +.codicon-debug-reverse-continue:before { content: "\eb8e" } +.codicon-debug-step-back:before { content: "\eb8f" } +.codicon-debug-restart-frame:before { content: "\eb90" } +.codicon-debug-alt:before { content: "\eb91" } +.codicon-call-incoming:before { content: "\eb92" } +.codicon-call-outgoing:before { content: "\eb93" } +.codicon-menu:before { content: "\eb94" } +.codicon-expand-all:before { content: "\eb95" } +.codicon-feedback:before { content: "\eb96" } +.codicon-group-by-ref-type:before { content: "\eb97" } +.codicon-ungroup-by-ref-type:before { content: "\eb98" } +.codicon-account:before { content: "\eb99" } +.codicon-bell-dot:before { content: "\eb9a" } +.codicon-debug-console:before { content: "\eb9b" } +.codicon-library:before { content: "\eb9c" } +.codicon-output:before { content: "\eb9d" } +.codicon-run-all:before { content: "\eb9e" } +.codicon-sync-ignored:before { content: "\eb9f" } +.codicon-pinned:before { content: "\eba0" } +.codicon-github-inverted:before { content: "\eba1" } +.codicon-server-process:before { content: "\eba2" } +.codicon-server-environment:before { content: "\eba3" } +.codicon-pass:before { content: "\eba4" } +.codicon-issue-closed:before { content: "\eba4" } +.codicon-stop-circle:before { content: "\eba5" } +.codicon-play-circle:before { content: "\eba6" } +.codicon-record:before { content: "\eba7" } +.codicon-debug-alt-small:before { content: "\eba8" } +.codicon-vm-connect:before { content: "\eba9" } +.codicon-cloud:before { content: "\ebaa" } +.codicon-merge:before { content: "\ebab" } +.codicon-export:before { content: "\ebac" } +.codicon-graph-left:before { content: "\ebad" } +.codicon-magnet:before { content: "\ebae" } +.codicon-notebook:before { content: "\ebaf" } +.codicon-redo:before { content: "\ebb0" } +.codicon-check-all:before { content: "\ebb1" } +.codicon-pinned-dirty:before { content: "\ebb2" } +.codicon-pass-filled:before { content: "\ebb3" } +.codicon-circle-large-filled:before { content: "\ebb4" } +.codicon-circle-large-outline:before { content: "\ebb5" } +.codicon-combine:before { content: "\ebb6" } +.codicon-gather:before { content: "\ebb6" } +.codicon-table:before { content: "\ebb7" } +.codicon-variable-group:before { content: "\ebb8" } +.codicon-type-hierarchy:before { content: "\ebb9" } +.codicon-type-hierarchy-sub:before { content: "\ebba" } +.codicon-type-hierarchy-super:before { content: "\ebbb" } +.codicon-git-pull-request-create:before { content: "\ebbc" } +.codicon-run-above:before { content: "\ebbd" } +.codicon-run-below:before { content: "\ebbe" } +.codicon-notebook-template:before { content: "\ebbf" } +.codicon-debug-rerun:before { content: "\ebc0" } +.codicon-workspace-trusted:before { content: "\ebc1" } +.codicon-workspace-untrusted:before { content: "\ebc2" } +.codicon-workspace-unknown:before { content: "\ebc3" } +.codicon-terminal-cmd:before { content: "\ebc4" } +.codicon-terminal-debian:before { content: "\ebc5" } +.codicon-terminal-linux:before { content: "\ebc6" } +.codicon-terminal-powershell:before { content: "\ebc7" } +.codicon-terminal-tmux:before { content: "\ebc8" } +.codicon-terminal-ubuntu:before { content: "\ebc9" } +.codicon-terminal-bash:before { content: "\ebca" } +.codicon-arrow-swap:before { content: "\ebcb" } +.codicon-copy:before { content: "\ebcc" } +.codicon-person-add:before { content: "\ebcd" } +.codicon-filter-filled:before { content: "\ebce" } +.codicon-wand:before { content: "\ebcf" } +.codicon-debug-line-by-line:before { content: "\ebd0" } +.codicon-inspect:before { content: "\ebd1" } +.codicon-layers:before { content: "\ebd2" } +.codicon-layers-dot:before { content: "\ebd3" } +.codicon-layers-active:before { content: "\ebd4" } +.codicon-compass:before { content: "\ebd5" } +.codicon-compass-dot:before { content: "\ebd6" } +.codicon-compass-active:before { content: "\ebd7" } +.codicon-azure:before { content: "\ebd8" } +.codicon-issue-draft:before { content: "\ebd9" } +.codicon-git-pull-request-closed:before { content: "\ebda" } +.codicon-git-pull-request-draft:before { content: "\ebdb" } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.ttf b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8d844c9279604c01d015aa1395051fb7e270e420 GIT binary patch literal 65608 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%0D9=G?+pucAU38?H}UL9qt!47 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 IN-TK)Hv!RQ;{X5v literal 0 HcmV?d00001 diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index 099ba92a18ee..4945269496ea 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -637,6 +637,16 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex }); function showHtmlPage(params : HtmlPageParams) { + function replaceAll(data: string, pattern: string, w: string): string { + for (;;) { + let n = data.replace(pattern, w); + if (n === data) { + return data; + } + data = n; + } + } + function showUri(url: string, id: string, name: string) { let uri = vscode.Uri.parse(url); var http = require('http'); @@ -658,7 +668,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex let view = vscode.window.createWebviewPanel(id, name, vscode.ViewColumn.One, { enableScripts: true, }); - view.webview.html = data; + view.webview.html = replaceAll(data, "{{BASE}}", url); }); }); request.on('error', function(e: any) { From 8765c56012551e1033fbe0504db1ad62d768058e Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Tue, 21 Sep 2021 07:28:52 +0200 Subject: [PATCH 09/38] tag has to be before any other links --- .../modules/java/lsp/server/htmlui/SimpleServer.java | 3 +++ .../java/lsp/server/htmlui/demo/HelloWorld.html | 4 ++-- java/java.lsp.server/vscode/src/extension.ts | 12 +----------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/SimpleServer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/SimpleServer.java index 441f3f199186..38689d53b752 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/SimpleServer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/SimpleServer.java @@ -384,6 +384,9 @@ private static void parseArgs(final Map context, final S if (args != null) { for (String arg : args.substring(1).split("&")) { String[] valueAndKey = arg.split("="); + if (valueAndKey.length != 2) { + continue; + } String key = valueAndKey[1].replaceAll("\\+", " "); for (int idx = 0;;) { diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html index e1d0dc8c6725..a75576eef865 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html @@ -3,8 +3,8 @@ - - + + Refactor: Change Signature diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index 4945269496ea..b8971ab6cc00 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -637,16 +637,6 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex }); function showHtmlPage(params : HtmlPageParams) { - function replaceAll(data: string, pattern: string, w: string): string { - for (;;) { - let n = data.replace(pattern, w); - if (n === data) { - return data; - } - data = n; - } - } - function showUri(url: string, id: string, name: string) { let uri = vscode.Uri.parse(url); var http = require('http'); @@ -668,7 +658,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex let view = vscode.window.createWebviewPanel(id, name, vscode.ViewColumn.One, { enableScripts: true, }); - view.webview.html = replaceAll(data, "{{BASE}}", url); + view.webview.html = data.replace("", ``); }); }); request.on('error', function(e: any) { From 7f84cede5881b8f03f002526ac4167cd56513e79 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 22 Sep 2021 08:26:45 +0200 Subject: [PATCH 10/38] Using enum to represent access modifiers --- .../server/htmlui/demo/HelloWorldCntrl.java | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java index 1389537e15fd..375a476452e2 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java @@ -26,12 +26,13 @@ import net.java.html.json.Function; import net.java.html.json.ModelOperation; import org.netbeans.api.htmlui.OpenHTMLRegistration; +import org.netbeans.modules.java.lsp.server.htmlui.demo.HelloWorldCntrl.Modifier; import org.openide.util.NbBundle; import org.openide.awt.ActionID; import org.openide.awt.StatusDisplayer; @Model(className = "HelloWorld", targetId = "", instance = true, builder = "with", properties = { - @Property(name = "selectedModifier", type = String.class), + @Property(name = "selectedModifier", type = Modifier.class), @Property(name = "name", type = String.class), @Property(name = "returnType", type = String.class), @Property(name = "parameters", type = Parameter.class, array = true) @@ -83,17 +84,38 @@ void removeParameter(HelloWorld model, Parameter data) { model.getParameters().remove(data); } + public enum Modifier { + PUBLIC("public"), PROTECTED("protected"), PACKAGE_PRIVATE("", "package private"), PRIVATE("private"); + + final String javaName; + final String humanName; + + Modifier(String javaName) { + this(javaName, null); + } + + Modifier(String javaName, String humanName) { + this.javaName = javaName; + this.humanName = humanName; + } + + @Override + public String toString() { + return humanName == null ? javaName : humanName; + } + } + @ComputedProperty - static List availableModifiers() { - return Arrays.asList("public", "protected", "package-package", "private"); + static List availableModifiers() { + return Arrays.asList(Modifier.values()); } @ComputedProperty static String preview( - String selectedModifier, String returnType, String name, List parameters + Modifier selectedModifier, String returnType, String name, List parameters ) { StringBuilder sb = new StringBuilder(); - sb.append(selectedModifier).append(" ").append(returnType); + sb.append(selectedModifier != null ? selectedModifier.javaName : "").append(" ").append(returnType); sb.append(" ").append(name).append("("); String sep = ""; for (Parameter p : parameters) { @@ -120,7 +142,7 @@ public static HelloWorld onPageLoad() { model. withName("openSource"). withReturnType("boolean"). - withSelectedModifier("public"). + withSelectedModifier(Modifier.PUBLIC). withParameters( new Parameter("Lookup.Provider", "project"), new Parameter("String", "className"), From a8dbba57d570aa080a9cf7ccea77c42b104faf17 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 1 Nov 2021 18:33:56 +0100 Subject: [PATCH 11/38] Use @HTMLDialog to display the Hello World UI --- .../server/htmlui/demo/HelloWorldCntrl.java | 20 +++--- .../server/protocol/WorkspaceServiceImpl.java | 12 ++-- .../org/netbeans/api/htmlui/HTMLDialog.java | 61 +++++++++---------- .../modules/htmlui/HTMLDialogBase.java | 50 +++++++++++++++ .../modules/htmlui/HTMLDialogImpl.java | 25 ++------ .../modules/htmlui/HTMLDialogView.java | 57 +++++++++++++++++ .../org/netbeans/modules/htmlui/HtmlPair.java | 4 ++ 7 files changed, 161 insertions(+), 68 deletions(-) create mode 100644 platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java create mode 100644 platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java index 375a476452e2..f1f8973390b3 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java @@ -25,6 +25,7 @@ import net.java.html.json.ComputedProperty; import net.java.html.json.Function; import net.java.html.json.ModelOperation; +import org.netbeans.api.htmlui.HTMLDialog; import org.netbeans.api.htmlui.OpenHTMLRegistration; import org.netbeans.modules.java.lsp.server.htmlui.demo.HelloWorldCntrl.Modifier; import org.openide.util.NbBundle; @@ -127,20 +128,12 @@ static String preview( return sb.toString(); } - @ActionID( - category = "Tools", - id = "org.netbeans.modules.java.lsp.server.protocol.HelloWorld" - ) @NbBundle.Messages("CTL_HelloWorld=Open HTML Hello World!") - @OpenHTMLRegistration( - url = "HelloWorld.html", - displayName = "#CTL_HelloWorld" - //, iconBase="SET/PATH/TO/ICON/HERE" - ) - public static HelloWorld onPageLoad() { + @HTMLDialog(url = "HelloWorld.html") + static HelloWorld showHelloWorld(String name) { final HelloWorld model = new HelloWorld(); model. - withName("openSource"). + withName(name). withReturnType("boolean"). withSelectedModifier(Modifier.PUBLIC). withParameters( @@ -155,6 +148,11 @@ public static HelloWorld onPageLoad() { return model.applyBindings(); } + public static void show() { + String ret = Pages.showHelloWorld("openSource"); + System.err.println("ret: " + ret); + } + static final class RefactoringData { } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java index f96c550029db..044fcdadcc7e 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java @@ -87,6 +87,8 @@ import org.netbeans.modules.java.lsp.server.Utils; import org.netbeans.modules.java.lsp.server.debugging.attach.AttachConfigurations; import org.netbeans.modules.java.lsp.server.debugging.attach.AttachNativeConfigurations; +import org.netbeans.modules.java.lsp.server.htmlui.demo.HelloWorld; +import org.netbeans.modules.java.lsp.server.htmlui.demo.HelloWorldCntrl; import org.netbeans.modules.java.source.ui.JavaSymbolProvider; import org.netbeans.modules.java.source.ui.JavaTypeProvider; import org.netbeans.modules.java.source.usages.ClassIndexImpl; @@ -96,7 +98,6 @@ import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.ProjectConfiguration; import org.netbeans.spi.project.ProjectConfigurationProvider; -import org.openide.awt.Actions; import org.openide.filesystems.FileObject; import org.openide.filesystems.URLMapper; import org.openide.util.Exceptions; @@ -134,8 +135,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { case Server.JAVA_NEW_PROJECT: return LspTemplateUI.createProject("Templates/Project", client, params); case Server.JAVA_HTML_DEMO: { - Action action = Actions.forID("Tools","org.netbeans.modules.java.lsp.server.protocol.HelloWorld"); - action.actionPerformed(new ActionEvent(this, 0, "")); + HelloWorldCntrl.show(); return CompletableFuture.completedFuture(true); } case Server.JAVA_BUILD_WORKSPACE: { @@ -254,10 +254,10 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString(); Position pos = gson.fromJson(gson.toJson(params.getArguments().get(1)), Position.class); return (CompletableFuture)((TextDocumentServiceImpl)server.getTextDocumentService()).superImplementations(uri, pos); - + case Server.JAVA_FIND_PROJECT_CONFIGURATIONS: { String fileUri = ((JsonPrimitive) params.getArguments().get(0)).getAsString(); - + FileObject file; try { file = URLMapper.findFileObject(new URL(fileUri)); @@ -343,7 +343,7 @@ private static Map attributesMap(JsonObject json) { } return map; } - + private CompletableFuture findProjectConfigurations(FileObject ownedFile) { return server.asyncOpenFileOwner(ownedFile).thenApply(p -> { if (p == null) { diff --git a/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java b/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java index ebc1fd1749ca..f0f49ec90d1b 100644 --- a/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java +++ b/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java @@ -27,9 +27,9 @@ import net.java.html.json.Model; import net.java.html.json.Property; import org.netbeans.html.context.spi.Contexts.Id; -import org.netbeans.modules.htmlui.HTMLDialogImpl; +import org.netbeans.modules.htmlui.HTMLDialogBase; -/** Generates method that opens an HTML based modal dialog. Sample of a typical +/** Generates method that opens an HTML based modal dialog. Sample of a typical * usage follows. * HTML Page dialog.html *
@@ -60,9 +60,9 @@
 
     {@link Override @Override} public void actionPerformed({@link ActionEvent} e) {
         // shows dialog with a question, checkbox is checked by default
-        // {@link #className() Pages} is automatically generated class 
+        // {@link #className() Pages} is automatically generated class
         String ret = Pages.showHelloWorld(true);
-        
+
         System.out.println("User selected: " + ret);
     }
 }
@@ -71,13 +71,13 @@
  * The method is generated into Pages class in the same package
  * (unless one changes the name via {@link #className()}) and has the same name,
  * and parameters as the method annotated by this annotation. When the method
- * is invoked, it opens a dialog, loads an HTML page into it. When the page is 
+ * is invoked, it opens a dialog, loads an HTML page into it. When the page is
  * loaded, it calls back the method annotated by this annotation and passes it
- * its own arguments. The method is supposed to make the page live, preferrably 
- * by using {@link net.java.html.json.Model} generated class and calling 
+ * its own arguments. The method is supposed to make the page live, preferrably
+ * by using {@link net.java.html.json.Model} generated class and calling
  * applyBindings() on it.
  * 

- * The HTML page may contain hidden <button> elements. If it does so, + * The HTML page may contain hidden <button> elements. If it does so, * those buttons are copied to the dialog frame and displayed underneath the page. * Their enabled/disabled state reflects the state of the buttons in the page. * When one of the buttons is selected, the dialog closes and the generated @@ -88,7 +88,7 @@ * <button> elements, two buttons are added. One representing * the OK choice (with id="OK") and one representing * the cancel choice (with null id). Both buttons are always - * enabled. One can check the + * enabled. One can check the * return value from the dialog showing method * to be "OK" to know whether the * user approved the dialog. @@ -102,17 +102,17 @@ * Will be resolved by the annotation processor and converted into * nbresloc protocol - as such the HTML page can be L10Ned * later by adding classical L10N suffixes. E.g. index_cs.html - * will take preceedence over index.html if the user is + * will take preceedence over index.html if the user is * running in Czech {@link Locale}. - * + * * @return relative path the HTML page */ String url(); - + /** Name of the file to generate the method that opens the dialog * into. Class of such name will be generated into the same - * package. - * + * package. + * * @return name of class to generate */ String className() default "Pages"; @@ -120,30 +120,29 @@ /** Selects some of provided technologies. The HTML/Java API @ version 1.1 * supports {@link Id technology ids}. One can specify the preferred ones * to use in this NetBeans component by using this attribute. - * + * * @return list of preferred technology ids * @since 1.3 */ String[] techIds() default {}; - - /** Rather than using this class directly, consider - * {@link HTMLDialog}. The {@link HTMLDialog} annotation + + /** Rather than using this class directly, consider + * {@link HTMLDialog}. The {@link HTMLDialog} annotation * generates boilderplate code for you * and can do some compile times checks helping you to warnings * as soon as possible. */ public static final class Builder { - private final HTMLDialogImpl impl; - + private final HTMLDialogBase impl; + private Builder(String u) { - impl = new HTMLDialogImpl(); - impl.setUrl(u); + impl = HTMLDialogBase.create(u); } /** Starts creation of a new HTML dialog. The page * can contain hidden buttons as described at * {@link HTMLDialog}. - * + * * @param url URL (usually using nbresloc protocol) * of the page to display in the dialog. * @return instance of the builder @@ -151,10 +150,10 @@ private Builder(String u) { public static Builder newDialog(String url) { return new Builder(url); } - + /** Registers a runnable to be executed when the page * becomes ready. - * + * * @param run runnable to run * @return this builder */ @@ -162,11 +161,11 @@ public Builder loadFinished(Runnable run) { impl.setOnPageLoad(run); return this; } - + /** Requests some of provided technologies. The HTML/Java API @ version 1.1 * supports {@link Id technology ids}. One can specify the preferred ones * to use in this NetBeans component by using calling this method. - * + * * @param ids list of preferred technology ids to add to the builder * @return instance of the builder * @since 1.3 @@ -177,20 +176,20 @@ public Builder addTechIds(String... ids) { } /** Displays the dialog. This method blocks waiting for the - * dialog to be shown and closed by the user. - * + * dialog to be shown and closed by the user. + * * @return 'id' of a selected button element or null * if the dialog was closed without selecting a button */ public String showAndWait() { return impl.showAndWait(); } - + /** Obtains the component from the builder. The parameter * can either be {@link javafx.embed.swing.JFXPanel}.class or * {@link javafx.scene.web.WebView}.class. After calling this * method the builder becomes useless. - * + * * @param requested component type * @param type either {@link javafx.embed.swing.JFXPanel} or {@link javafx.scene.web.WebView} class * @return instance of the requested component diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java new file mode 100644 index 000000000000..89d52a196196 --- /dev/null +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.htmlui; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public abstract class HTMLDialogBase { + List techIds = new ArrayList<>(); + final String url; + Runnable onPageLoad; + + HTMLDialogBase(String url) { + this.url = url; + } + + + public abstract String showAndWait(); + public abstract C component(Class type); + + public void addTechIds(String[] ids) { + this.techIds.addAll(Arrays.asList(ids)); + } + + public void setOnPageLoad(Runnable onPageLoad) { + this.onPageLoad = onPageLoad; + } + + public static HTMLDialogBase create(String url) { + HtmlPair view = HtmlPair.newView(); + return view.isDefault() ? new HTMLDialogImpl(url) : new HTMLDialogView(url, view); + } +} diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java index 6e1bcbdb0e41..eb9a690ba28c 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java @@ -25,38 +25,23 @@ import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import javax.swing.JButton; import javax.swing.JComponent; import org.openide.*; import org.openide.util.Exceptions; import org.openide.util.Lookup; -public final class HTMLDialogImpl implements Runnable { +final class HTMLDialogImpl extends HTMLDialogBase implements Runnable { private volatile int state; private JComponent p; private DialogDescriptor dd; private Object webView; - - private String url; - private Runnable onPageLoad; - private List techIds = new ArrayList<>(); private boolean nestedLoop; - public void setUrl(String url) { - this.url = url; + HTMLDialogImpl(String url) { + super(url); } - public void setOnPageLoad(Runnable onPageLoad) { - this.onPageLoad = onPageLoad; - } - - public void addTechIds(String[] ids) { - this.techIds.addAll(Arrays.asList(ids)); - } - @Override public void run() { switch (state) { @@ -117,7 +102,7 @@ private void showDialog() { Dialog d = DialogDisplayer.getDefault().createDialog(dd); d.setVisible(true); } - + private void initPanel() { p = HtmlToolkit.getDefault().newPanel(); dd = new DialogDescriptor(p, ""); @@ -125,7 +110,7 @@ private void initPanel() { state = 1; HtmlToolkit.getDefault().execute(this); } - + private void initPage() { try { onPageLoad.run(); diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java new file mode 100644 index 000000000000..c22576ba3b7a --- /dev/null +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.htmlui; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import javax.swing.JButton; +import org.openide.util.Exceptions; + +final class HTMLDialogView extends HTMLDialogBase { + private final HtmlPair view; + + public HTMLDialogView(String url, HtmlPair view) { + super(url); + this.view = view; + } + + @Override + public String showAndWait() { + view.makeVisible(() -> { + try { + view.load(getClass().getClassLoader(), new URL(url), () -> { + onPageLoad.run(); + JButton[] b = Buttons.buttons(); + System.err.println("butt: " + Arrays.toString(b)); + return null; + }, this.techIds.toArray(new String[0])); + } catch (MalformedURLException ex) { + Exceptions.printStackTrace(ex); + } + }); + return null; + } + + @Override + public C component(Class type) { + return null; + } + +} diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java index df101a9f993e..b8ee4993c0c8 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java @@ -65,4 +65,8 @@ final void makeVisible(Runnable whenReady) { final void load(ClassLoader loader, URL pageUrl, Callable initialize, String... techIds) { viewer.load(view, loader, pageUrl, initialize, techIds); } + + final boolean isDefault() { + return this.viewer == HtmlComponent.VIEWER; + } } From 54ddd6ffacd6709c06b793981eafa7b6c9fdc8ab Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Fri, 5 Nov 2021 14:24:29 +0100 Subject: [PATCH 12/38] ChangeMethodParameters refactoring modified to use the WebView based UI. --- .../server/htmlui/demo/HelloWorldCntrl.java | 158 --------- .../ChangeMethodParametersRefactoring.java | 273 -------------- .../server/protocol/CodeActionsProvider.java | 4 +- .../java/lsp/server/protocol/Server.java | 1 - .../server/protocol/WorkspaceServiceImpl.java | 8 - .../ChangeMethodParametersRefactoring.java | 333 ++++++++++++++++++ .../CodeRefactoring.java | 5 +- ...tractSuperclassOrInterfaceRefactoring.java | 7 +- .../MoveRefactoring.java | 6 +- .../PullUpRefactoring.java | 6 +- .../PushDownRefactoring.java | 6 +- .../ui/ChangeMethodParameters.html} | 31 +- .../demo => refactoring/ui}/codicon.css | 0 .../demo => refactoring/ui}/codicon.ttf | Bin .../ui/refactoring.css} | 76 +++- .../java/lsp/server/protocol/ServerTest.java | 23 +- java/java.lsp.server/vscode/package.json | 5 - java/java.lsp.server/vscode/src/extension.ts | 11 +- 18 files changed, 454 insertions(+), 499 deletions(-) delete mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java delete mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ChangeMethodParametersRefactoring.java create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java rename java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/{protocol => refactoring}/CodeRefactoring.java (96%) rename java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/{protocol => refactoring}/ExtractSuperclassOrInterfaceRefactoring.java (96%) rename java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/{protocol => refactoring}/MoveRefactoring.java (97%) rename java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/{protocol => refactoring}/PullUpRefactoring.java (97%) rename java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/{protocol => refactoring}/PushDownRefactoring.java (96%) rename java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/{htmlui/demo/HelloWorld.html => refactoring/ui/ChangeMethodParameters.html} (52%) rename java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/{htmlui/demo => refactoring/ui}/codicon.css (100%) rename java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/{htmlui/demo => refactoring/ui}/codicon.ttf (100%) rename java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/{htmlui/demo/HelloWorld.css => refactoring/ui/refactoring.css} (55%) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java deleted file mode 100644 index f1f8973390b3..000000000000 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorldCntrl.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.netbeans.modules.java.lsp.server.htmlui.demo; - -import java.util.Arrays; -import java.util.List; -import net.java.html.json.Model; -import net.java.html.json.Property; -import net.java.html.json.ComputedProperty; -import net.java.html.json.Function; -import net.java.html.json.ModelOperation; -import org.netbeans.api.htmlui.HTMLDialog; -import org.netbeans.api.htmlui.OpenHTMLRegistration; -import org.netbeans.modules.java.lsp.server.htmlui.demo.HelloWorldCntrl.Modifier; -import org.openide.util.NbBundle; -import org.openide.awt.ActionID; -import org.openide.awt.StatusDisplayer; - -@Model(className = "HelloWorld", targetId = "", instance = true, builder = "with", properties = { - @Property(name = "selectedModifier", type = Modifier.class), - @Property(name = "name", type = String.class), - @Property(name = "returnType", type = String.class), - @Property(name = "parameters", type = Parameter.class, array = true) -}) -public final class HelloWorldCntrl { - @Model(className = "Parameter", properties = { - @Property(name = "type", type = String.class), - @Property(name = "name", type = String.class) - }) - static class ParameterCntrl { - } - - private RefactoringData data; - - @ModelOperation - void assignData(HelloWorld model, RefactoringData data) { - this.data = data; - } - - @Function - void doRefactoring(HelloWorld model) { - StatusDisplayer.getDefault().setStatusText("use data: " + data + " and model " + model); - } - - @Function - void moveUpParameter(HelloWorld model, Parameter data) { - final List arr = model.getParameters(); - int index = arr.indexOf(data); - if (index > 0) { - Parameter other = arr.get(index - 1); - arr.set(index, other); - arr.set(index - 1, data); - } - } - - @Function - void moveDownParameter(HelloWorld model, Parameter data) { - final List arr = model.getParameters(); - int index = arr.indexOf(data); - if (index != -1 && index + 1 < arr.size()) { - Parameter other = arr.get(index + 1); - arr.set(index, other); - arr.set(index + 1, data); - } - } - - @Function - void removeParameter(HelloWorld model, Parameter data) { - model.getParameters().remove(data); - } - - public enum Modifier { - PUBLIC("public"), PROTECTED("protected"), PACKAGE_PRIVATE("", "package private"), PRIVATE("private"); - - final String javaName; - final String humanName; - - Modifier(String javaName) { - this(javaName, null); - } - - Modifier(String javaName, String humanName) { - this.javaName = javaName; - this.humanName = humanName; - } - - @Override - public String toString() { - return humanName == null ? javaName : humanName; - } - } - - @ComputedProperty - static List availableModifiers() { - return Arrays.asList(Modifier.values()); - } - - @ComputedProperty - static String preview( - Modifier selectedModifier, String returnType, String name, List parameters - ) { - StringBuilder sb = new StringBuilder(); - sb.append(selectedModifier != null ? selectedModifier.javaName : "").append(" ").append(returnType); - sb.append(" ").append(name).append("("); - String sep = ""; - for (Parameter p : parameters) { - sb.append(sep); - sb.append(p.getType()).append(" ").append(p.getName()); - sep = ", "; - } - sb.append(")"); - return sb.toString(); - } - - @NbBundle.Messages("CTL_HelloWorld=Open HTML Hello World!") - @HTMLDialog(url = "HelloWorld.html") - static HelloWorld showHelloWorld(String name) { - final HelloWorld model = new HelloWorld(); - model. - withName(name). - withReturnType("boolean"). - withSelectedModifier(Modifier.PUBLIC). - withParameters( - new Parameter("Lookup.Provider", "project"), - new Parameter("String", "className"), - new Parameter("String", "methodName"), - new Parameter("String", "signature"), - new Parameter("int", "line") - ). - assignData(new RefactoringData()); - - return model.applyBindings(); - } - - public static void show() { - String ret = Pages.showHelloWorld("openSource"); - System.err.println("ret: " + ret); - } - - static final class RefactoringData { - } -} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ChangeMethodParametersRefactoring.java deleted file mode 100644 index 849b4b6804b5..000000000000 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ChangeMethodParametersRefactoring.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.netbeans.modules.java.lsp.server.protocol; - -import com.google.gson.Gson; -import com.sun.source.tree.BlockTree; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.StatementTree; -import com.sun.source.tree.Tree; -import com.sun.source.util.SourcePositions; -import com.sun.source.util.TreePath; -import com.sun.source.util.Trees; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeKind; -import org.eclipse.lsp4j.ApplyWorkspaceEditParams; -import org.eclipse.lsp4j.CodeAction; -import org.eclipse.lsp4j.CodeActionKind; -import org.eclipse.lsp4j.CodeActionParams; -import org.eclipse.lsp4j.MessageParams; -import org.eclipse.lsp4j.MessageType; -import org.netbeans.api.java.source.ClasspathInfo; -import org.netbeans.api.java.source.CompilationController; -import org.netbeans.api.java.source.CompilationInfo; -import org.netbeans.api.java.source.ElementHandle; -import org.netbeans.api.java.source.JavaSource; -import org.netbeans.api.java.source.SourceUtils; -import org.netbeans.api.java.source.TreePathHandle; -import org.netbeans.api.java.source.TreeUtilities; -import org.netbeans.modules.editor.java.Utilities; -import org.netbeans.modules.java.lsp.server.Utils; -import org.netbeans.modules.parsing.api.ResultIterator; -import org.netbeans.modules.refactoring.java.api.ChangeParametersRefactoring; -import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; -import org.openide.filesystems.FileObject; -import org.openide.util.NbBundle; -import org.openide.util.lookup.ServiceProvider; - -/** - * - * @author Dusan Balek - */ -@ServiceProvider(service = CodeActionsProvider.class, position = 200) -public final class ChangeMethodParametersRefactoring extends CodeRefactoring { - - private static final String CHANGE_METHOD_PARAMS_REFACTORING_KIND = "refactor.change.method.params"; - private static final String CHANGE_METHOD_PARAMS_REFACTORING_COMMAND = "java.refactor.change.method.params"; - - private final Set commands = Collections.singleton(CHANGE_METHOD_PARAMS_REFACTORING_COMMAND); - private final Gson gson = new Gson(); - - @Override - @NbBundle.Messages({ - "DN_ChangeMethodParams=Change Method Parameters...", - }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { - List only = params.getContext().getOnly(); - if (only == null || !only.contains(CodeActionKind.Refactor)) { - return Collections.emptyList(); - } - CompilationController info = CompilationController.get(resultIterator.getParserResult()); - if (info == null || !JavaRefactoringUtils.isRefactorable(info.getFileObject())) { - return Collections.emptyList(); - } - info.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); - int offset = getOffset(info, params.getRange().getStart()); - Trees trees = info.getTrees(); - TreePath path = info.getTreeUtilities().pathFor(offset); - Tree.Kind kind = null; - while (path != null && (kind = path.getLeaf().getKind()) != Tree.Kind.METHOD && kind != Tree.Kind.METHOD_INVOCATION && kind != Tree.Kind.NEW_CLASS && kind != Tree.Kind.MEMBER_REFERENCE) { - path = path.getParentPath(); - } - Element element = null; - FileObject elementSource = null; - if (kind == Tree.Kind.METHOD_INVOCATION || kind == Tree.Kind.NEW_CLASS || kind == Tree.Kind.MEMBER_REFERENCE) { - element = trees.getElement(path); - if (element == null || element.asType().getKind() == TypeKind.ERROR) { - return Collections.emptyList(); - } - elementSource = SourceUtils.getFile(ElementHandle.create(element), info.getClasspathInfo()); - } - if (elementSource == null) { - return Collections.emptyList(); - } - QuickPickItem elementItem = new QuickPickItem(createLabel(info, element, true)); - elementItem.setUserData(new ElementData(element)); - return Collections.singletonList(createCodeAction(Bundle.DN_ChangeMethodParams(), CHANGE_METHOD_PARAMS_REFACTORING_KIND, CHANGE_METHOD_PARAMS_REFACTORING_COMMAND, Utils.toUri(elementSource), elementItem)); - } - - @Override - public Set getCommands() { - return commands; - } - - @Override - @NbBundle.Messages({ - "DN_ChangeMethodSignature=Change method signature", - }) - public CompletableFuture processCommand(NbCodeLanguageClient client, String command, List arguments) { - try { - if (arguments.size() > 1) { - String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); - QuickPickItem sourceItem = gson.fromJson(gson.toJson(arguments.get(1)), QuickPickItem.class); - String label = sourceItem.getLabel(); - int idx = label.indexOf('('); - client.showInputBox(new ShowInputBoxParams(Bundle.DN_ChangeMethodSignature(), label.substring(idx))).thenAccept(signature -> { - if (signature != null && !signature.isEmpty()) { - changeMethodParams(client, uri, sourceItem, signature); - } - }); - } else { - throw new IllegalArgumentException(String.format("Illegal number of arguments received for command: %s", command)); - } - } catch (Exception ex) { - client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); - } - return CompletableFuture.completedFuture(true); - } - - private void changeMethodParams(NbCodeLanguageClient client, String uri, QuickPickItem source, String signature) { - try { - FileObject file = Utils.fromUri(uri); - ClasspathInfo info = ClasspathInfo.create(file); - JavaSource js = JavaSource.forFileObject(file); - if (js == null) { - throw new IOException("Cannot get JavaSource for: " + uri); - } - ElementHandle handle = gson.fromJson(gson.toJson(source.getUserData()), ElementData.class).toHandle(); - AtomicReference params = new AtomicReference<>(); - StringBuilder ret = new StringBuilder(); - js.runUserActionTask(ci -> { - ci.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); - ExecutableElement method = (ExecutableElement) handle.resolve(ci); - if (method != null) { - TreePath path = ci.getTrees().getPath(method); - if (path != null) { - ExecutableElement el = fromSignature(ci, signature, path); - if (el != null) { - if (method.getReturnType() != el.getReturnType()) { - ret.append(Utilities.getTypeName(ci, el.getReturnType(), true)); - } - params.set(matchParameters(ci, el.getParameters(), method.getParameters())); - } - } - } - }, true); - if (params.get() == null) { - throw new IllegalArgumentException("Error while parsing new method signature."); - } - ChangeParametersRefactoring refactoring = new ChangeParametersRefactoring(TreePathHandle.from(handle, info)); - refactoring.setReturnType(ret.length() > 0 ? ret.toString() : null); - refactoring.setParameterInfo(params.get()); - refactoring.getContext().add(JavaRefactoringUtils.getClasspathInfoFor(file)); - client.applyEdit(new ApplyWorkspaceEditParams(perform(refactoring, "ChangeMethodParameters"))); - } catch (Exception ex) { - client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); - } - } - - private static ExecutableElement fromSignature(CompilationInfo info, String signature, TreePath path) { - int idx = signature.lastIndexOf(':'); - StringBuilder toParse = new StringBuilder("{class _X { public "); - if (idx < 0) { - toParse.append("_X").append(signature); - } else { - toParse.append(signature.substring(idx + 1)).append(" m").append(signature.substring(0, idx)); - } - toParse.append("{}}}"); - SourcePositions[] sp = new SourcePositions[1]; - TreeUtilities treeUtilities = info.getTreeUtilities(); - StatementTree stmt = treeUtilities.parseStatement(toParse.toString(), sp); - if (stmt != null && stmt.getKind() == Tree.Kind.BLOCK) { - treeUtilities.attributeTree(stmt, info.getTrees().getScope(path)); - List stmts = ((BlockTree) stmt).getStatements(); - if (!stmts.isEmpty() && stmts.get(0).getKind() == Tree.Kind.CLASS) { - ClassTree ct = (ClassTree) stmts.get(0); - for (Tree member : ct.getMembers()) { - TreePath memberPath = new TreePath(path, member); - if (!treeUtilities.isSynthetic(memberPath) && member.getKind() == Tree.Kind.METHOD) { - Element element = info.getTrees().getElement(memberPath); - if (element != null && (element.getKind() == ElementKind.METHOD || element.getKind() == ElementKind.CONSTRUCTOR)) { - return (ExecutableElement) element; - } - } - } - } - } - return null; - } - - private static ChangeParametersRefactoring.ParameterInfo[] matchParameters(CompilationInfo info, List params, List orig) { - ChangeParametersRefactoring.ParameterInfo[] result = new ChangeParametersRefactoring.ParameterInfo[params.size()]; - boolean[] used = new boolean[orig.size()]; - for (int idx = 0; idx < params.size(); idx++) { - VariableElement param = params.get(idx); - for (int i = 0; i < orig.size(); i++) { - if (!used[i]) { - VariableElement origParam = orig.get(i); - if (origParam.getSimpleName().contentEquals(param.getSimpleName())) { - result[idx] = new ChangeParametersRefactoring.ParameterInfo(i, param.getSimpleName().toString(), Utilities.getTypeName(info, param.asType(), true).toString(), null); - used[i] = true; - } - } - } - } - for (int idx = 0; idx < params.size(); idx++) { - if (result[idx] == null) { - VariableElement param = params.get(idx); - for (int i = 0; i < orig.size(); i++) { - if (!used[i]) { - VariableElement origParam = orig.get(i); - if (origParam.asType() == param.asType()) { - result[idx] = new ChangeParametersRefactoring.ParameterInfo(i, param.getSimpleName().toString(), Utilities.getTypeName(info, param.asType(), true).toString(), null); - used[i] = true; - } - } - } - } - } - for (int idx = 0; idx < params.size(); idx++) { - if (result[idx] == null) { - VariableElement param = params.get(idx); - result[idx] = idx >= orig.size() || used[idx] - ? new ChangeParametersRefactoring.ParameterInfo(-1, param.getSimpleName().toString(), Utilities.getTypeName(info, param.asType(), true).toString(), defaultValue(param)) - : new ChangeParametersRefactoring.ParameterInfo(idx, param.getSimpleName().toString(), Utilities.getTypeName(info, param.asType(), true).toString(), null); - } - } - return result; - } - - private static String defaultValue(VariableElement param) { - switch(param.asType().getKind()) { - case ARRAY: - case DECLARED: - return "null"; - case BOOLEAN: - return "false"; - case BYTE: - case CHAR: - case DOUBLE: - case FLOAT: - case INT: - case LONG: - case SHORT: - return "0"; - } - return null; - } -} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java index db57677d3db3..631377c13989 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java @@ -138,11 +138,11 @@ public ElementData(ElementHandle handle) { this.signature = ElementHandleAccessor.getInstance().getJVMSignature(handle); } - ElementHandle toHandle() { + public ElementHandle toHandle() { return ElementHandleAccessor.getInstance().create(ElementKind.valueOf(kind), signature); } - Element resolve(CompilationInfo info) { + public Element resolve(CompilationInfo info) { return toHandle().resolve(info); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java index ed6beb64e8c9..193d74581e72 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java @@ -632,7 +632,6 @@ private InitializeResult constructInitResponse(JavaSource src) { JAVA_LOAD_WORKSPACE_TESTS, JAVA_NEW_FROM_TEMPLATE, JAVA_NEW_PROJECT, - JAVA_HTML_DEMO, JAVA_PROJECT_CONFIGURATION_COMPLETION, JAVA_SUPER_IMPLEMENTATION, NATIVE_IMAGE_FIND_DEBUG_PROCESS_TO_ATTACH)); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java index 294f3c999535..2b2078113a2e 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java @@ -23,7 +23,6 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.sun.source.util.TreePath; -import java.awt.event.ActionEvent; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -49,7 +48,6 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; -import javax.swing.Action; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.DidChangeWatchedFilesParams; @@ -88,8 +86,6 @@ import org.netbeans.modules.java.lsp.server.Utils; import org.netbeans.modules.java.lsp.server.debugging.attach.AttachConfigurations; import org.netbeans.modules.java.lsp.server.debugging.attach.AttachNativeConfigurations; -import org.netbeans.modules.java.lsp.server.htmlui.demo.HelloWorld; -import org.netbeans.modules.java.lsp.server.htmlui.demo.HelloWorldCntrl; import org.netbeans.modules.java.source.ui.JavaSymbolProvider; import org.netbeans.modules.java.source.ui.JavaTypeProvider; import org.netbeans.modules.java.source.usages.ClassIndexImpl; @@ -135,10 +131,6 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { return LspTemplateUI.createFromTemplate("Templates", client, params); case Server.JAVA_NEW_PROJECT: return LspTemplateUI.createProject("Templates/Project", client, params); - case Server.JAVA_HTML_DEMO: { - HelloWorldCntrl.show(); - return CompletableFuture.completedFuture(true); - } case Server.JAVA_BUILD_WORKSPACE: { final CommandProgress progressOfCompilation = new CommandProgress(); final Lookup ctx = Lookups.singleton(progressOfCompilation); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java new file mode 100644 index 000000000000..485c6bc1e6a7 --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -0,0 +1,333 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.java.lsp.server.refactoring; + +import com.google.gson.Gson; +import com.sun.source.tree.Tree; +import com.sun.source.util.TreePath; +import com.sun.source.util.Trees; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeKind; +import net.java.html.json.ComputedProperty; +import net.java.html.json.Function; +import net.java.html.json.Model; +import net.java.html.json.ModelOperation; +import net.java.html.json.Property; +import org.eclipse.lsp4j.ApplyWorkspaceEditParams; +import org.eclipse.lsp4j.CodeAction; +import org.eclipse.lsp4j.CodeActionKind; +import org.eclipse.lsp4j.CodeActionParams; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.MessageType; +import org.netbeans.api.htmlui.HTMLDialog; +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.api.java.source.TreePathHandle; +import org.netbeans.modules.editor.java.Utilities; +import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.parsing.api.ResultIterator; +import org.netbeans.modules.refactoring.java.api.ChangeParametersRefactoring; +import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author Dusan Balek + */ +@ServiceProvider(service = CodeActionsProvider.class, position = 200) +public final class ChangeMethodParametersRefactoring extends CodeRefactoring { + + private static final String CHANGE_METHOD_PARAMS_REFACTORING_KIND = "refactor.change.method.params"; + private static final String CHANGE_METHOD_PARAMS_REFACTORING_COMMAND = "java.refactor.change.method.params"; + + private final Set commands = Collections.singleton(CHANGE_METHOD_PARAMS_REFACTORING_COMMAND); + private final Gson gson = new Gson(); + + @Override + @NbBundle.Messages({ + "DN_ChangeMethodParams=Change Method Parameters...", + }) + public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + List only = params.getContext().getOnly(); + if (only == null || !only.contains(CodeActionKind.Refactor)) { + return Collections.emptyList(); + } + CompilationController info = CompilationController.get(resultIterator.getParserResult()); + if (info == null || !JavaRefactoringUtils.isRefactorable(info.getFileObject())) { + return Collections.emptyList(); + } + info.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); + int offset = getOffset(info, params.getRange().getStart()); + Trees trees = info.getTrees(); + TreePath path = info.getTreeUtilities().pathFor(offset); + Tree.Kind kind = null; + while (path != null && (kind = path.getLeaf().getKind()) != Tree.Kind.METHOD && kind != Tree.Kind.METHOD_INVOCATION && kind != Tree.Kind.NEW_CLASS && kind != Tree.Kind.MEMBER_REFERENCE) { + path = path.getParentPath(); + } + Element element = null; + FileObject elementSource = null; + if (kind == Tree.Kind.METHOD || kind == Tree.Kind.METHOD_INVOCATION || kind == Tree.Kind.NEW_CLASS || kind == Tree.Kind.MEMBER_REFERENCE) { + element = trees.getElement(path); + if (element == null || element.asType().getKind() == TypeKind.ERROR) { + return Collections.emptyList(); + } + elementSource = SourceUtils.getFile(ElementHandle.create(element), info.getClasspathInfo()); + } + if (elementSource == null) { + return Collections.emptyList(); + } + QuickPickItem elementItem = new QuickPickItem(createLabel(info, element, true)); + elementItem.setUserData(new ElementData(element)); + return Collections.singletonList(createCodeAction(Bundle.DN_ChangeMethodParams(), CHANGE_METHOD_PARAMS_REFACTORING_KIND, CHANGE_METHOD_PARAMS_REFACTORING_COMMAND, Utils.toUri(elementSource), elementItem)); + } + + @Override + public Set getCommands() { + return commands; + } + + @Override + @NbBundle.Messages({ + "DN_ChangeMethodSignature=Change method signature", + }) + public CompletableFuture processCommand(NbCodeLanguageClient client, String command, List arguments) { + try { + if (arguments.size() > 1) { + String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); + QuickPickItem sourceItem = gson.fromJson(gson.toJson(arguments.get(1)), QuickPickItem.class); + ElementHandle handle = gson.fromJson(gson.toJson(sourceItem.getUserData()), ElementData.class).toHandle(); + FileObject file = Utils.fromUri(uri); + JavaSource js = JavaSource.forFileObject(file); + if (js != null) { + js.runUserActionTask(ci -> { + ci.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); + ExecutableElement method = (ExecutableElement) handle.resolve(ci); + if (method != null) { + ParameterUI[] params = new ParameterUI[method.getParameters().size()]; + for (int i = 0; i < method.getParameters().size(); i++) { + VariableElement param = method.getParameters().get(i); + ChangeParametersRefactoring.ParameterInfo info = new ChangeParametersRefactoring.ParameterInfo(i, param.getSimpleName().toString(), Utilities.getTypeName(ci, param.asType(), true).toString(), null); + params[i] = new ParameterUI(info.getType(), info.getName()); + params[i].assignInfo(info); + } + Modifier mod; + if (method.getModifiers().contains(javax.lang.model.element.Modifier.PUBLIC)) { + mod = Modifier.PUBLIC; + } else if (method.getModifiers().contains(javax.lang.model.element.Modifier.PROTECTED)) { + mod = Modifier.PROTECTED; + } else if (method.getModifiers().contains(javax.lang.model.element.Modifier.PRIVATE)) { + mod = Modifier.PRIVATE; + } else { + mod = Modifier.PACKAGE_PRIVATE; + } + ChangeMethodParameterUI model = new ChangeMethodParameterUI(); + model.withName(method.getSimpleName().toString()) + .withReturnType(Utilities.getTypeName(ci, method.getReturnType(), true).toString()) + .withSelectedModifier(mod) + .withParameters(params) + .assignData(client, file, TreePathHandle.from(handle, ClasspathInfo.create(file))); + Pages.showChangeMethodParametersUI(model); + } + }, true); + } + } else { + throw new IllegalArgumentException(String.format("Illegal number of arguments received for command: %s", command)); + } + } catch (Exception ex) { + client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + } + return CompletableFuture.completedFuture(true); + } + + private static String defaultValue(String type) { + switch(type) { + case "boolean": + return "false"; + case "byte": + case "char": + case "double": + case "float": + case "int": + case "long": + case "short": + return "0"; + } + return "null"; + } + + @HTMLDialog(url = "ui/ChangeMethodParameters.html") + static ChangeMethodParameterUI showChangeMethodParametersUI(ChangeMethodParameterUI ui) { + return ui.applyBindings(); + } + + @Model(className = "ChangeMethodParameterUI", targetId = "", instance = true, builder = "with", properties = { + @Property(name = "selectedModifier", type = Modifier.class), + @Property(name = "name", type = String.class), + @Property(name = "returnType", type = String.class), + @Property(name = "parameters", type = ParameterUI.class, array = true) + }) + static final class MethodControl { + + private NbCodeLanguageClient client; + private FileObject file; + private TreePathHandle handle; + + @ModelOperation + void assignData(ChangeMethodParameterUI ui, NbCodeLanguageClient client, FileObject file, TreePathHandle handle) { + this.client = client; + this.file = file; + this.handle = handle; + } + + @Function + void doRefactoring(ChangeMethodParameterUI ui) { + try { + ChangeParametersRefactoring refactoring = new ChangeParametersRefactoring(handle); + String returnType = ui.getReturnType(); + refactoring.setReturnType(returnType.length() > 0 ? returnType : null); + List parameters = ui.getParameters(); + ChangeParametersRefactoring.ParameterInfo[] params = new ChangeParametersRefactoring.ParameterInfo[parameters.size()]; + for (int i = 0; i < parameters.size(); i++) { + ParameterUI parameter = parameters.get(i); + parameter.getInfo(i, (idx, info) -> { + params[idx] = info != null ? info : new ChangeParametersRefactoring.ParameterInfo(-1, parameter.getName(), parameter.getType(), defaultValue(parameter.getType())); + }); + } + refactoring.setParameterInfo(params); + refactoring.getContext().add(JavaRefactoringUtils.getClasspathInfoFor(file)); + client.applyEdit(new ApplyWorkspaceEditParams(perform(refactoring, "ChangeMethodParameters"))); + } catch (Exception ex) { + client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + } + } + + @Function + void moveUpParameter(ChangeMethodParameterUI ui, ParameterUI data) { + final List arr = ui.getParameters(); + int index = arr.indexOf(data); + if (index > 0) { + ParameterUI other = arr.get(index - 1); + arr.set(index, other); + arr.set(index - 1, data); + } + } + + @Function + void moveDownParameter(ChangeMethodParameterUI ui, ParameterUI data) { + final List arr = ui.getParameters(); + int index = arr.indexOf(data); + if (index != -1 && index + 1 < arr.size()) { + ParameterUI other = arr.get(index + 1); + arr.set(index, other); + arr.set(index + 1, data); + } + } + + @Function + void addParameter(ChangeMethodParameterUI ui) { + ui.getParameters().add(new ParameterUI()); + } + + @Function + void removeParameter(ChangeMethodParameterUI ui, ParameterUI data) { + ui.getParameters().remove(data); + } + + @Function + void cancel(ChangeMethodParameterUI ui) { + } + + @ComputedProperty + static List availableModifiers() { + return Arrays.asList(Modifier.values()); + } + + @ComputedProperty + static String preview( + Modifier selectedModifier, String returnType, String name, List parameters + ) { + StringBuilder sb = new StringBuilder(); + sb.append(selectedModifier != null ? selectedModifier.javaName : "").append(" ").append(returnType); + sb.append(" ").append(name).append("("); + String sep = ""; + for (ParameterUI p : parameters) { + sb.append(sep); + sb.append(p.getType()).append(" ").append(p.getName()); + sep = ", "; + } + sb.append(")"); + return sb.toString(); + } + } + + @Model(className = "ParameterUI", instance = true, properties = { + @Property(name = "type", type = String.class), + @Property(name = "name", type = String.class) + }) + static final class ParamControl { + private ChangeParametersRefactoring.ParameterInfo info; + + @ModelOperation + void assignInfo(ParameterUI model, ChangeParametersRefactoring.ParameterInfo info) { + this.info = info; + } + + @ModelOperation + void getInfo(ParameterUI model, int idx, BiConsumer consumer) { + consumer.accept(idx, info); + } + } + + static enum Modifier { + PUBLIC("public"), PROTECTED("protected"), PACKAGE_PRIVATE("", "package private"), PRIVATE("private"); + + final String javaName; + final String humanName; + + Modifier(String javaName) { + this(javaName, null); + } + + Modifier(String javaName, String humanName) { + this.javaName = javaName; + this.humanName = humanName; + } + + @Override + public String toString() { + return humanName == null ? javaName : humanName; + } + } +} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/CodeRefactoring.java similarity index 96% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/CodeRefactoring.java index 01494f56b8e7..15545494df6d 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/CodeRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import java.io.File; import java.net.URL; @@ -39,6 +39,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.netbeans.api.java.source.ModificationResult; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; import org.netbeans.modules.refactoring.api.AbstractRefactoring; import org.netbeans.modules.refactoring.api.Problem; import org.netbeans.modules.refactoring.api.RefactoringSession; @@ -57,7 +58,7 @@ */ public abstract class CodeRefactoring extends CodeActionsProvider { - protected final WorkspaceEdit perform(AbstractRefactoring refactoring, String name) throws Exception { + protected static final WorkspaceEdit perform(AbstractRefactoring refactoring, String name) throws Exception { RefactoringSession session = RefactoringSession.create(name); Problem p = refactoring.checkParameters(); if (p != null && p.isFatal()) { diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ExtractSuperclassOrInterfaceRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java similarity index 96% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ExtractSuperclassOrInterfaceRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java index 87d4807d3392..e22bbf9be723 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ExtractSuperclassOrInterfaceRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import com.google.gson.Gson; import com.sun.source.tree.ClassTree; @@ -54,6 +54,11 @@ import org.netbeans.api.java.source.TreePathHandle; import org.netbeans.api.java.source.TreeUtilities; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.java.lsp.server.protocol.ShowInputBoxParams; +import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.refactoring.api.AbstractRefactoring; import org.netbeans.modules.refactoring.java.api.ExtractInterfaceRefactoring; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/MoveRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java similarity index 97% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/MoveRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java index 9aa18d7c425d..87cc06357ecc 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/MoveRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import com.google.gson.Gson; import com.sun.source.tree.ClassTree; @@ -55,6 +55,10 @@ import org.netbeans.api.project.ProjectUtils; import org.netbeans.api.project.SourceGroup; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.refactoring.java.api.JavaMoveMembersProperties; import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PullUpRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java similarity index 97% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PullUpRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java index b146688fc303..a4320aaa8d3d 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PullUpRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import com.google.gson.Gson; import com.sun.source.tree.ClassTree; @@ -55,6 +55,10 @@ import org.netbeans.api.java.source.TreePathHandle; import org.netbeans.api.java.source.TreeUtilities; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; import org.netbeans.modules.refactoring.java.api.MemberInfo; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PushDownRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java similarity index 96% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PushDownRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java index 591f07108349..9c5d0657be8d 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PushDownRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import com.google.gson.Gson; import com.sun.source.tree.ClassTree; @@ -51,6 +51,10 @@ import org.netbeans.api.java.source.TreePathHandle; import org.netbeans.api.java.source.TreeUtilities; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; import org.netbeans.modules.refactoring.java.api.MemberInfo; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html similarity index 52% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html index a75576eef865..d50cba4d6cb4 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.html +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html @@ -1,14 +1,16 @@ + + - + - Refactor: Change Signature + Refactor: Change Method Parameters... - +
@@ -26,29 +28,32 @@
- - - + + +
- - - + + +
+
+ +
- +
-

.

+

- - + +
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.css b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.css similarity index 100% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.css rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.css diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.ttf b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.ttf similarity index 100% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/codicon.ttf rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.ttf diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.css b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/refactoring.css similarity index 55% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.css rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/refactoring.css index 29475004deb7..921a2ece293e 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/demo/HelloWorld.css +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/refactoring.css @@ -27,42 +27,75 @@ select { padding: 4px !important; } button { - font-size: 13px; + cursor: pointer; +} +label { + display: block; + margin-bottom: 5px; + user-select: none; +} +.vscode-font { + font-family: var(--vscode-font-family); + font-size: var(--vscode-font-size); text-decoration: none; +} +.button-text { + margin-left: 5px; + vertical-align: text-top; +} +.regular-button { border: none; - background: var(--vscode-button-background); - color: var(--vscode-button-foreground); - font-family: var(--vscode-font-family) !important; padding: 4px 10px 4px 10px; margin: 5px; - cursor: pointer; + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-background); } -button:hover, button:focus { +.regular-button:hover, .regular-button:focus { background: var(--vscode-button-hoverBackground); } -button:focus { +.regular-button:focus { outline: 1px solid var(--vscode-button-hoverBackground); outline-offset: 2px; } -label { - display: block; - margin-bottom: 5px; +.silent-button { + border: none; + padding: 4px 10px 4px 10px; + margin: 5px; + color: var(--vscode-input-foreground); + background-color: var(--vscode-list-hoverBackground); } -.caption1 { - margin-bottom: -20px !important; +.silent-button:hover { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-hoverBackground); } -.caption2 { - margin-bottom: -20px !important; - margin-left: -32px; +.silent-button:focus { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-hoverBackground); + outline: 1px solid var(--vscode-button-hoverBackground); + outline-offset: 2px; } -.action { - border-radius: 4px; +.action-button { + border: none; + border-radius: 4px; padding: 2px; margin: 3px 0px; + color: var(--vscode-input-foreground); + background-color: transparent; } -.action:hover { +.action-button:hover { background-color: var(--vscode-list-inactiveSelectionBackground); } +.action-button:focus, .action-button:hover:focus { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-hoverBackground); + outline: none; +} +.params-caption { + margin-bottom: 8px; +} +.filler { + width: 53px; +} .preview-panel { margin: 0px; padding: 10px; @@ -92,6 +125,9 @@ label { .row:hover { background-color: var(--vscode-list-hoverBackground); } +.row:focus-within { + background-color: var(--vscode-tab-unfocusedInactiveModifiedBorder); +} .flex { display: flex; } @@ -106,3 +142,7 @@ label { .align-right { margin-left: auto; } +.add-param { + padding: 0px 15px; + padding-top: 2px; +} \ No newline at end of file diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java index ffb698009c8f..96f29e1a1865 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java @@ -4072,7 +4072,7 @@ public CompletableFuture showInputBox(ShowInputBoxParams params) { @Override public CompletableFuture> showQuickPick(ShowQuickPickParams params) { List items = params.getItems(); - return CompletableFuture.completedFuture(Bundle.DN_SelectTargetPackage().equals(params.getPlaceHolder()) ? items.subList(2, 3) : items.subList(0, 1)); + return CompletableFuture.completedFuture("Select target package".equals(params.getPlaceHolder()) ? items.subList(2, 3) : items.subList(0, 1)); } @Override @@ -4093,7 +4093,7 @@ public void showStatusBarMessage(ShowStatusMessageParams params) { codeActions.stream() .filter(Either::isRight) .map(Either::getRight) - .filter(a -> Bundle.DN_Move().equals(a.getTitle())) + .filter(a -> "Move...".equals(a.getTitle())) .findAny(); assertTrue(move.isPresent()); server.getWorkspaceService().executeCommand(new ExecuteCommandParams(move.get().getCommand().getCommand(), move.get().getCommand().getArguments())).get(); @@ -4232,7 +4232,7 @@ public CompletableFuture showInputBox(ShowInputBoxParams params) { @Override public CompletableFuture> showQuickPick(ShowQuickPickParams params) { List items = params.getItems(); - return CompletableFuture.completedFuture(Bundle.DN_SelectTargetPackage().equals(params.getPlaceHolder()) ? items.subList(1, 2) : items.subList(0, 1)); + return CompletableFuture.completedFuture("Select target package".equals(params.getPlaceHolder()) ? items.subList(1, 2) : items.subList(0, 1)); } @Override @@ -4253,7 +4253,7 @@ public void showStatusBarMessage(ShowStatusMessageParams params) { codeActions.stream() .filter(Either::isRight) .map(Either::getRight) - .filter(a -> Bundle.DN_Move().equals(a.getTitle())) + .filter(a -> "Move...".equals(a.getTitle())) .findAny(); assertTrue(move.isPresent()); server.getWorkspaceService().executeCommand(new ExecuteCommandParams(move.get().getCommand().getCommand(), move.get().getCommand().getArguments())).get(); @@ -4402,7 +4402,7 @@ public void showStatusBarMessage(ShowStatusMessageParams params) { codeActions.stream() .filter(Either::isRight) .map(Either::getRight) - .filter(a -> Bundle.DN_ExtractInterface().equals(a.getTitle())) + .filter(a -> "Extract Interface...".equals(a.getTitle())) .findAny(); assertTrue(extractInterface.isPresent()); server.getWorkspaceService().executeCommand(new ExecuteCommandParams(extractInterface.get().getCommand().getCommand(), extractInterface.get().getCommand().getArguments())).get(); @@ -4567,7 +4567,7 @@ public void showStatusBarMessage(ShowStatusMessageParams params) { codeActions.stream() .filter(Either::isRight) .map(Either::getRight) - .filter(a -> Bundle.DN_ExtractSuperclass().equals(a.getTitle())) + .filter(a -> "Extract Superclass...".equals(a.getTitle())) .findAny(); assertTrue(extractSuperclass.isPresent()); server.getWorkspaceService().executeCommand(new ExecuteCommandParams(extractSuperclass.get().getCommand().getCommand(), extractSuperclass.get().getCommand().getArguments())).get(); @@ -4754,7 +4754,7 @@ public void showHtmlPage(HtmlPageParams params) { codeActions.stream() .filter(Either::isRight) .map(Either::getRight) - .filter(a -> Bundle.DN_PullUp().equals(a.getTitle())) + .filter(a -> "Pull Up...".equals(a.getTitle())) .findAny(); assertTrue(pullUp.isPresent()); server.getWorkspaceService().executeCommand(new ExecuteCommandParams(pullUp.get().getCommand().getCommand(), pullUp.get().getCommand().getArguments())).get(); @@ -4902,7 +4902,7 @@ public void showHtmlPage(HtmlPageParams params) { codeActions.stream() .filter(Either::isRight) .map(Either::getRight) - .filter(a -> Bundle.DN_PushDown().equals(a.getTitle())) + .filter(a -> "Push Down...".equals(a.getTitle())) .findAny(); assertTrue(pushDown.isPresent()); server.getWorkspaceService().executeCommand(new ExecuteCommandParams(pushDown.get().getCommand().getCommand(), pushDown.get().getCommand().getArguments())).get(); @@ -5044,6 +5044,11 @@ public CompletableFuture> showQuickPick(ShowQuickPickParams public void showStatusBarMessage(ShowStatusMessageParams params) { throw new UnsupportedOperationException("Not supported yet."); } + + @Override + public void showHtmlPage(HtmlPageParams params) { + throw new UnsupportedOperationException(); + } }, client.getInputStream(), client.getOutputStream()); serverLauncher.startListening(); LanguageServer server = serverLauncher.getRemoteProxy(); @@ -5058,7 +5063,7 @@ public void showStatusBarMessage(ShowStatusMessageParams params) { codeActions.stream() .filter(Either::isRight) .map(Either::getRight) - .filter(a -> Bundle.DN_ChangeMethodParams().equals(a.getTitle())) + .filter(a -> "Change Method Parameters...".equals(a.getTitle())) .findAny(); assertTrue(changeMethodParams.isPresent()); server.getWorkspaceService().executeCommand(new ExecuteCommandParams(changeMethodParams.get().getCommand().getCommand(), changeMethodParams.get().getCommand().getArguments())).get(); diff --git a/java/java.lsp.server/vscode/package.json b/java/java.lsp.server/vscode/package.json index 2b73a98d1f35..fd73dc308a82 100644 --- a/java/java.lsp.server/vscode/package.json +++ b/java/java.lsp.server/vscode/package.json @@ -319,11 +319,6 @@ } ], "commands": [ - { - "command": "java.workspace.html.demo", - "title": "Demo HTML UI", - "category": "Java" - }, { "command": "java.workspace.compile", "title": "Compile Workspace", diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index f42f7c1fd253..47b4aafa817d 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -241,9 +241,6 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { throw `Client ${c} doesn't support new project`; } })); - context.subscriptions.push(commands.registerCommand('java.workspace.html.demo', () => { - vscode.commands.executeCommand('java.html.demo'); - })); context.subscriptions.push(commands.registerCommand('java.workspace.compile', () => { return window.withProgress({ location: ProgressLocation.Window }, p => { return new Promise(async (resolve, reject) => { @@ -661,7 +658,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex }); function showHtmlPage(params : HtmlPageParams) { - function showUri(url: string, id: string, name: string) { + function showUri(url: string) { let uri = vscode.Uri.parse(url); var http = require('http'); @@ -679,7 +676,9 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex data += chunk; }); res.on('end', function() { - let view = vscode.window.createWebviewPanel(id, name, vscode.ViewColumn.One, { + const match = /(.*)<\/title>/i.exec(data); + const name = match && match.length > 1 ? match[1] : '' + let view = vscode.window.createWebviewPanel('htmlView', name, vscode.ViewColumn.Beside, { enableScripts: true, }); view.webview.html = data.replace("<head>", `<head><base href="${url}">`); @@ -690,7 +689,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex }); request.end(); } - showUri(params.uri, "test", "Showing a view"); + showUri(params.uri); } function showStatusBarMessage(params : ShowStatusMessageParams) { From 93e6ddc6b300e0a645c1b7971d34ef863f4aa832 Mon Sep 17 00:00:00 2001 From: Dusan Balek <dusan.balek@oracle.com> Date: Mon, 8 Nov 2021 10:22:57 +0100 Subject: [PATCH 13/38] Allow for existing parameters changes. --- .../refactoring/ChangeMethodParametersRefactoring.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java index 485c6bc1e6a7..1d13b066e530 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -222,7 +222,11 @@ void doRefactoring(ChangeMethodParameterUI ui) { for (int i = 0; i < parameters.size(); i++) { ParameterUI parameter = parameters.get(i); parameter.getInfo(i, (idx, info) -> { - params[idx] = info != null ? info : new ChangeParametersRefactoring.ParameterInfo(-1, parameter.getName(), parameter.getType(), defaultValue(parameter.getType())); + if (info != null) { + params[idx] = new ChangeParametersRefactoring.ParameterInfo(info.getOriginalIndex(), parameter.getName(), parameter.getType(), null); + } else { + params[idx] = new ChangeParametersRefactoring.ParameterInfo(-1, parameter.getName(), parameter.getType(), defaultValue(parameter.getType())); + } }); } refactoring.setParameterInfo(params); From 3d60d40ca55d6cf1051f9404e57fe7d09254c59e Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Tue, 16 Nov 2021 06:34:53 +0100 Subject: [PATCH 14/38] Making HTML/Java Refactoring UI testable --- .../ChangeMethodParametersRefactoring.java | 59 ++++--- .../java/lsp/server/protocol/ServerTest.java | 5 +- .../java/lsp/server/ui/MockHtmlViewer.java | 153 ++++++++++++++++++ 3 files changed, 190 insertions(+), 27 deletions(-) create mode 100644 java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/MockHtmlViewer.java diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java index 485c6bc1e6a7..9a15251ef6d1 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -135,30 +135,7 @@ public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, Str ci.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); ExecutableElement method = (ExecutableElement) handle.resolve(ci); if (method != null) { - ParameterUI[] params = new ParameterUI[method.getParameters().size()]; - for (int i = 0; i < method.getParameters().size(); i++) { - VariableElement param = method.getParameters().get(i); - ChangeParametersRefactoring.ParameterInfo info = new ChangeParametersRefactoring.ParameterInfo(i, param.getSimpleName().toString(), Utilities.getTypeName(ci, param.asType(), true).toString(), null); - params[i] = new ParameterUI(info.getType(), info.getName()); - params[i].assignInfo(info); - } - Modifier mod; - if (method.getModifiers().contains(javax.lang.model.element.Modifier.PUBLIC)) { - mod = Modifier.PUBLIC; - } else if (method.getModifiers().contains(javax.lang.model.element.Modifier.PROTECTED)) { - mod = Modifier.PROTECTED; - } else if (method.getModifiers().contains(javax.lang.model.element.Modifier.PRIVATE)) { - mod = Modifier.PRIVATE; - } else { - mod = Modifier.PACKAGE_PRIVATE; - } - ChangeMethodParameterUI model = new ChangeMethodParameterUI(); - model.withName(method.getSimpleName().toString()) - .withReturnType(Utilities.getTypeName(ci, method.getReturnType(), true).toString()) - .withSelectedModifier(mod) - .withParameters(params) - .assignData(client, file, TreePathHandle.from(handle, ClasspathInfo.create(file))); - Pages.showChangeMethodParametersUI(model); + Pages.showChangeMethodParametersUI(ci, client, file, handle, method); } }, true); } @@ -188,8 +165,37 @@ private static String defaultValue(String type) { } @HTMLDialog(url = "ui/ChangeMethodParameters.html") - static ChangeMethodParameterUI showChangeMethodParametersUI(ChangeMethodParameterUI ui) { - return ui.applyBindings(); + static ChangeMethodParameterUI showChangeMethodParametersUI( + CompilationController ci, + NbCodeLanguageClient client, + FileObject file, + ElementHandle handle, + ExecutableElement method + ) { + ParameterUI[] params = new ParameterUI[method.getParameters().size()]; + for (int i = 0; i < method.getParameters().size(); i++) { + VariableElement param = method.getParameters().get(i); + ChangeParametersRefactoring.ParameterInfo info = new ChangeParametersRefactoring.ParameterInfo(i, param.getSimpleName().toString(), Utilities.getTypeName(ci, param.asType(), true).toString(), null); + params[i] = new ParameterUI(info.getType(), info.getName()); + params[i].assignInfo(info); + } + Modifier mod; + if (method.getModifiers().contains(javax.lang.model.element.Modifier.PUBLIC)) { + mod = Modifier.PUBLIC; + } else if (method.getModifiers().contains(javax.lang.model.element.Modifier.PROTECTED)) { + mod = Modifier.PROTECTED; + } else if (method.getModifiers().contains(javax.lang.model.element.Modifier.PRIVATE)) { + mod = Modifier.PRIVATE; + } else { + mod = Modifier.PACKAGE_PRIVATE; + } + ChangeMethodParameterUI model = new ChangeMethodParameterUI(); + model.withName(method.getSimpleName().toString()) + .withReturnType(Utilities.getTypeName(ci, method.getReturnType(), true).toString()) + .withSelectedModifier(mod) + .withParameters(params) + .assignData(client, file, TreePathHandle.from(handle, ClasspathInfo.create(file))); + return model.applyBindings(); } @Model(className = "ChangeMethodParameterUI", targetId = "", instance = true, builder = "with", properties = { @@ -211,6 +217,7 @@ void assignData(ChangeMethodParameterUI ui, NbCodeLanguageClient client, FileObj this.handle = handle; } + @ModelOperation @Function void doRefactoring(ChangeMethodParameterUI ui) { try { diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java index 1f0b6ca37de0..28c12c65deee 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java @@ -147,6 +147,8 @@ import org.netbeans.api.sendopts.CommandLine; import org.netbeans.junit.NbTestCase; import org.netbeans.modules.java.hints.infrastructure.JavaErrorProvider; +import org.netbeans.modules.java.lsp.server.refactoring.ChangeMethodParameterUI; +import org.netbeans.modules.java.lsp.server.ui.MockHtmlViewer; import org.netbeans.modules.java.source.BootClassPathUtil; import org.netbeans.modules.parsing.impl.indexing.implspi.CacheFolderProvider; import org.netbeans.spi.java.classpath.ClassPathProvider; @@ -5047,7 +5049,8 @@ public void showStatusBarMessage(ShowStatusMessageParams params) { @Override public void showHtmlPage(HtmlPageParams params) { - throw new UnsupportedOperationException(); + ChangeMethodParameterUI ui = MockHtmlViewer.assertDialogShown(params.getUri(), ChangeMethodParameterUI.class); + ui.doRefactoring(); } }, client.getInputStream(), client.getOutputStream()); serverLauncher.startListening(); diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/MockHtmlViewer.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/MockHtmlViewer.java new file mode 100644 index 000000000000..c6bd94c91871 --- /dev/null +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/MockHtmlViewer.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.java.lsp.server.ui; + +import java.io.Closeable; +import java.io.Reader; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; +import net.java.html.BrwsrCtx; +import static org.junit.Assert.assertTrue; +import org.netbeans.html.boot.spi.Fn; +import org.netbeans.html.context.spi.Contexts; +import org.netbeans.html.json.spi.FunctionBinding; +import org.netbeans.html.json.spi.PropertyBinding; +import org.netbeans.html.json.spi.Technology; +import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams; +import org.netbeans.spi.htmlui.HtmlViewer; +import org.openide.util.lookup.ServiceProvider; + +@ServiceProvider(service = HtmlViewer.class) +public final class MockHtmlViewer extends AbstractLspHtmlViewer { + private static final Map<String, BrwsrCtx> data = Collections.synchronizedMap(new HashMap<>()); + + @Override + public void load(View view, ClassLoader loader, URL pageUrl, Callable<Object> initialize, String[] techIds) { + UIContext ui = UIContext.find(); + String key = UUID.randomUUID().toString(); + + BrwsrCtx ctx = mockPresenter(); + ctx.execute(() -> { + Object v; + try (Closeable c = Fn.activate(Contexts.find(ctx, Fn.Presenter.class))) { + v = initialize.call(); + } catch (Exception ex) { + MockTech.exception(ctx, ex); + } + data.put(key, ctx); + ui.showHtmlPage(new HtmlPageParams(key)); + }); + } + + public static <T> T assertDialogShown(String uri, Class<T> clazz) { + Object v = MockTech.applied(data.get(uri)); + if (v instanceof Exception) { + throw new AssertionError((Exception)v); + } + assertTrue("Expecting " + clazz + " but was " + v, clazz.isInstance(v)); + return clazz.cast(v); + } + + private BrwsrCtx mockPresenter() { + final Fn.Presenter p = new Fn.Presenter() { + @Override + public Fn defineFn(String string, String... strings) { + return new Fn() { + @Override + public Object invoke(Object o, Object... os) throws Exception { + return new Object[0]; + } + }; + } + + @Override + public void displayPage(URL url, Runnable r) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void loadScript(Reader reader) throws Exception { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + }; + return new MockTech().register(Contexts.newBuilder(p)).register(Fn.Presenter.class, p, 10).build(); + } + + private static class MockTech implements Technology { + + Object applied; + + public MockTech() { + } + + Contexts.Builder register(Contexts.Builder b) { + return b.register(MockTech.class, this, 10).register(Technology.class, this, 10); + } + + static void exception(BrwsrCtx ctx, Exception ex) { + Contexts.find(ctx, MockTech.class).applied = ex; + } + + static Object applied(BrwsrCtx ctx) { + return Contexts.find(ctx, MockTech.class).applied; + } + + @Override + public Object wrapModel(Object o) { + return o; + } + + @Override + public Object toModel(Class type, Object o) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void bind(PropertyBinding pb, Object o, Object data) { + } + + @Override + public void valueHasMutated(Object data, String string) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void expose(FunctionBinding fb, Object o, Object data) { + } + + @Override + public void applyBindings(Object data) { + this.applied = data; + } + + @Override + public Object wrapArray(Object[] os) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void runSafe(Runnable r) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + } +} From a4ff70256a657ad57c21ba8cbccee65c5d63fdef Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Tue, 16 Nov 2021 06:58:08 +0100 Subject: [PATCH 15/38] NotificationType has one type parameter --- java/java.lsp.server/vscode/src/protocol.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java/java.lsp.server/vscode/src/protocol.ts b/java/java.lsp.server/vscode/src/protocol.ts index 7749a4c4b9cf..570794d1e90b 100644 --- a/java/java.lsp.server/vscode/src/protocol.ts +++ b/java/java.lsp.server/vscode/src/protocol.ts @@ -22,7 +22,8 @@ import * as vscode from 'vscode'; import { ProtocolNotificationType, ProtocolRequestType, - ShowMessageParams + ShowMessageParams, + NotificationType } from 'vscode-languageclient'; import { Position, @@ -41,7 +42,7 @@ export interface HtmlPageParams { } export namespace HtmlPageRequest { - export const type = new NotificationType<HtmlPageParams, void>('window/showHtmlPage'); + export const type = new NotificationType<HtmlPageParams>('window/showHtmlPage'); }; export namespace StatusMessageRequest { From 720e9ad9369551fcfa755324ba5c6ed5baf045db Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Tue, 16 Nov 2021 11:27:38 +0100 Subject: [PATCH 16/38] Straightforward way to closeWindow via message to WebView --- .../ChangeMethodParametersRefactoring.java | 11 +++++++++++ java/java.lsp.server/vscode/src/extension.ts | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java index 9a15251ef6d1..fd4d6bab5017 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -32,6 +32,7 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; +import net.java.html.js.JavaScriptBody; import net.java.html.json.ComputedProperty; import net.java.html.json.Function; import net.java.html.json.Model; @@ -235,6 +236,7 @@ void doRefactoring(ChangeMethodParameterUI ui) { refactoring.setParameterInfo(params); refactoring.getContext().add(JavaRefactoringUtils.getClasspathInfoFor(file)); client.applyEdit(new ApplyWorkspaceEditParams(perform(refactoring, "ChangeMethodParameters"))); + closeWindow(); } catch (Exception ex) { client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); } @@ -274,8 +276,17 @@ void removeParameter(ChangeMethodParameterUI ui, ParameterUI data) { @Function void cancel(ChangeMethodParameterUI ui) { + closeWindow(); } + @JavaScriptBody(args = {}, body = "\n" + + "const vscode = acquireVsCodeApi();\n" // this method can be called only once per WebView existance + + "vscode.postMessage({\n" + + " command: 'dispose',\n" + + "});\n" + ) + private static native void closeWindow(); + @ComputedProperty static List<Modifier> availableModifiers() { return Arrays.asList(Modifier.values()); diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index 2e0f290375fe..8991cd93f400 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -701,6 +701,13 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex enableScripts: true, }); view.webview.html = data.replace("<head>", `<head><base href="${url}">`); + view.webview.onDidReceiveMessage(message => { + switch (message.command) { + case 'dispose': + view.dispose(); + break; + } + }); }); }); request.on('error', function(e: any) { From 9cfeb4c6e53c705187d55a5c594814c9f4e9ffa3 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Wed, 24 Nov 2021 06:19:47 +0100 Subject: [PATCH 17/38] Specify urlOpener as Consumer --- .../java/lsp/server/htmlui/Browser.java | 33 +++++++++++++------ .../lsp/server/ui/AbstractLspHtmlViewer.java | 19 ++++------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Browser.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Browser.java index ae395f2d869a..e901edf43ba8 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Browser.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Browser.java @@ -42,6 +42,7 @@ import java.util.Queue; import java.util.UUID; import java.util.concurrent.Executor; +import java.util.function.Consumer; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -64,7 +65,7 @@ * </dependency> * </pre> */ -public abstract class Browser implements Fn.Presenter, Fn.KeepAlive, Flushable, +public final class Browser implements Fn.Presenter, Fn.KeepAlive, Flushable, Executor, Closeable { static final Logger LOG = Logger.getLogger(Browser.class.getName()); private final Map<String,Command> SESSIONS = new HashMap<>(); @@ -151,8 +152,9 @@ static HttpServer findServer(Object obj) { * @param page the page to display in the browser * @throws IOException if something goes wrong */ - protected abstract void show(URI page) throws IOException; - + void show(URI page) throws IOException { + config.getBrowser().accept(page); + } @Override public Fn defineFn(String string, String... strings) { throw new UnsupportedOperationException(); @@ -210,7 +212,7 @@ public final void displayPage(URL page, Runnable onPageLoad) { * constructor. */ public final static class Config { - String browser; + private Consumer<URI> browser; Integer port; boolean debug = Boolean.getBoolean("com.dukescript.presenters.browserDebug"); @@ -218,6 +220,7 @@ public final static class Config { * Default constructor. */ public Config() { + command(null); } private Config(Config copy) { @@ -246,7 +249,20 @@ private Config(Config copy) { * @return this instance */ public Config command(String executable) { - this.browser = executable; + this.browser = (page) -> { + String impl = executable; + if (impl == null) { + impl = System.getProperty("com.dukescript.presenters.browser"); // NOI18N + } + if ("none".equalsIgnoreCase(impl)) { // NOI18N + return; + } + // Show.show(impl, page); TBD + }; + return this; + } + public Config browser(Consumer<URI> urlOpener) { + this.browser = urlOpener; return this; } @@ -273,11 +289,8 @@ public Config debug(boolean debug) { return this; } - final String getBrowser() { - if (browser != null) { - return browser; - } - return System.getProperty("com.dukescript.presenters.browser"); // NOI18N + final Consumer<URI> getBrowser() { + return browser; } final int getPort() { diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java index 91f6a2d1cfee..8b925b6ee585 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java @@ -18,8 +18,6 @@ */ package org.netbeans.modules.java.lsp.server.ui; -import java.io.IOException; -import java.net.URI; import java.net.URL; import java.util.concurrent.Callable; import org.netbeans.html.boot.spi.Fn; @@ -47,19 +45,16 @@ public void load(View view, ClassLoader loader, URL pageUrl, Callable<Object> in UIContext ui = UIContext.find(); Browser.Config c = new Browser.Config(); - Fn.Presenter b = new Browser(c) { - @Override - protected void show(URI page) throws IOException { - try { - ui.showHtmlPage(new HtmlPageParams(page.toASCIIString())); - } catch (Exception ex) { - Exceptions.printStackTrace(ex); - } + c.browser((page) -> { + try { + ui.showHtmlPage(new HtmlPageParams(page.toASCIIString())); + } catch (Exception ex) { + Exceptions.printStackTrace(ex); } - }; + }); + Fn.Presenter b = new Browser(c); b.displayPage(pageUrl, () -> { try { -// ui.showStatusMessage(new ShowStatusMessageParams(MessageType.Error, "http://localhost:" + port)); Object v = initialize.call(); System.err.println("v: " + v); } catch (Exception ex) { From c851ff41a5b5f40ccc63341cbbc69874df08a9e5 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Wed, 24 Nov 2021 11:20:33 +0100 Subject: [PATCH 18/38] Let the infrastructure render the buttons --- .../ChangeMethodParametersRefactoring.java | 29 +++++-- .../ui/ChangeMethodParameters.html | 6 +- .../lsp/server/ui/AbstractLspHtmlViewer.java | 32 ++++++++ .../org/netbeans/modules/htmlui/Buttons.java | 70 +++++++++-------- .../modules/htmlui/HTMLDialogImpl.java | 77 +++++++++++++++---- .../modules/htmlui/HTMLDialogView.java | 73 ++++++++++++++++-- .../modules/htmlui/HtmlComponent.java | 6 ++ .../org/netbeans/modules/htmlui/HtmlPair.java | 5 ++ .../org/netbeans/spi/htmlui/HtmlViewer.java | 2 + 9 files changed, 238 insertions(+), 62 deletions(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java index 662adff98b91..413c67e96639 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -22,6 +22,7 @@ import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; import com.sun.source.util.Trees; +import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -61,6 +62,7 @@ import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; import org.openide.filesystems.FileObject; import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; import org.openide.util.lookup.ServiceProvider; /** @@ -132,13 +134,24 @@ public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, Str FileObject file = Utils.fromUri(uri); JavaSource js = JavaSource.forFileObject(file); if (js != null) { - js.runUserActionTask(ci -> { - ci.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); - ExecutableElement method = (ExecutableElement) handle.resolve(ci); - if (method != null) { - Pages.showChangeMethodParametersUI(ci, client, file, handle, method); + return CompletableFuture.supplyAsync(() -> { + try { + js.runUserActionTask(ci -> { + ci.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); + ExecutableElement method = (ExecutableElement) handle.resolve(ci); + if (method != null) { + ChangeMethodParameterUI[] model = { null }; + String res = Pages.showChangeMethodParametersUI(ci, client, file, handle, method, model); + if ("accept".equals(res)) { + model[0].doRefactoring(); + } + } + }, true); + return null; + } catch (IOException ex) { + throw new IllegalStateException(ex); } - }, true); + }, RequestProcessor.getDefault()); } } else { throw new IllegalArgumentException(String.format("Illegal number of arguments received for command: %s", command)); @@ -171,7 +184,8 @@ static ChangeMethodParameterUI showChangeMethodParametersUI( NbCodeLanguageClient client, FileObject file, ElementHandle handle, - ExecutableElement method + ExecutableElement method, + ChangeMethodParameterUI[] modelBack ) { ParameterUI[] params = new ParameterUI[method.getParameters().size()]; for (int i = 0; i < method.getParameters().size(); i++) { @@ -196,6 +210,7 @@ static ChangeMethodParameterUI showChangeMethodParametersUI( .withSelectedModifier(mod) .withParameters(params) .assignData(client, file, TreePathHandle.from(handle, ClasspathInfo.create(file))); + modelBack[0] = model; return model.applyBindings(); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html index d50cba4d6cb4..cbd231f1aa41 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html @@ -51,9 +51,9 @@ <div class="section1"> <p class="preview-panel" data-bind="text: preview"></p> </div> - <div class="flex section"> - <button id="accept" class="regular-button vscode-font align-right" data-bind="click: doRefactoring">Refactor</button> - <button id="reject" class="regular-button vscode-font" data-bind="click: cancel">Cancel</button> + <div> + <button id="accept" hidden class="regular-button vscode-font align-right">Refactor</button> + <button id="reject" hidden class="regular-button vscode-font">Cancel</button> </div> </body> </html> diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java index 8b925b6ee585..9484d000e863 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java @@ -20,6 +20,8 @@ import java.net.URL; import java.util.concurrent.Callable; +import java.util.function.Consumer; +import net.java.html.js.JavaScriptBody; import org.netbeans.html.boot.spi.Fn; import org.netbeans.modules.java.lsp.server.htmlui.Browser; import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams; @@ -63,6 +65,36 @@ public void load(View view, ClassLoader loader, URL pageUrl, Callable<Object> in }); } + @Override + public Object createButton(String id, Consumer<String> callback) { + return createButton0(id, callback); + } + + @JavaScriptBody(args = { "id", "callback" }, javacall = true, body = "\n" + + "var first = false;\n" + + "var footer = document.getElementById('dialog-buttons');\n" + + "if (!footer) {\n" + + " first = true\n" + + " footer = document.createElement('div');\n" + + " footer.id = 'dialog-buttons';\n" + + " footer.classList.add('flex');\n" + + " footer.classList.add('section');\n" + + " document.body.appendChild(footer);\n" + + "}\n" + + "var button = document.createElement('button');\n" + + "button.id = id;\n" + + "button.onclick = function() {;\n" + + " callback.@java.util.function.Consumer::accept(Ljava/lang/Object;)(id);\n" + + "};\n" + + "button.classList.add('regular-button');\n" + + "button.classList.add('vscode-font');\n" + + "if (first) {\n" + + " button.classList.add('align-right');\n" + + "}\n" + + "footer.appendChild(button);\n" + + "return button;\n" + ) + native static Object createButton0(String id, Consumer<?> callback); public static final class View { public View() { diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java index 21c86bb8233a..91fc79a58076 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java @@ -18,10 +18,11 @@ */ package org.netbeans.modules.htmlui; -import java.awt.EventQueue; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import javax.swing.JButton; +import java.util.Objects; +import java.util.function.Consumer; import net.java.html.js.JavaScriptBody; import org.openide.util.NbBundle; @@ -29,8 +30,14 @@ * * @author Jaroslav Tulach <jtulach@netbeans.org> */ -final class Buttons { - private final List<JButton> arr = new ArrayList<>(); +abstract class Buttons<Button> { + protected abstract Button createButton(String name); + protected abstract String getName(Button b); + protected abstract void setText(Button b, String text); + protected abstract void setEnabled(Button b, boolean enabled); + protected abstract void runLater(Runnable r); + + private final List<Button> arr = new ArrayList<>(); @JavaScriptBody(args = {}, javacall = true, body = "var self = this;\n" + @@ -43,11 +50,6 @@ final class Buttons { " }\n" + " target.addEventListener('DOMSubtreeModified', l, false);\n" + "}\n" + - "var l = function(changes) { throw 'Here';\n" + - " for (var i = 0; i < changes.length; i++) {\n" + - " var b = changes[i].target;\n" + - " };\n" + - "};\n" + "for (var i = 0; i < list.length; i++) {\n" + " var b = list[i];\n" + " if (b.hidden === true) {\n" + @@ -62,14 +64,11 @@ final class Buttons { private native Object[] list(); final void changeState(final String id, final boolean disabled, final String text) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - for (JButton b : arr) { - if (b.getName().equals(id)) { - b.setEnabled(!disabled); - b.setText(text); - } + runLater(() -> { + for (Button b : arr) { + if (Objects.equals(getName(b), id)) { + setEnabled(b, !disabled); + setText(b, text); } } }); @@ -79,24 +78,27 @@ public void run() { "CTL_OK=OK", "CTL_Cancel=Cancel", }) - public static JButton[] buttons() { - final Buttons btns = new Buttons(); - final Object[] all = btns.list(); - for (int i = 0; i < all.length; i += 3) { - JButton b = new JButton(); - b.setName(all[i].toString()); - b.setText(all[i + 1].toString()); - if (Boolean.TRUE.equals(all[i + 2])) { - b.setEnabled(false); + public List<Button> buttons() { + if (arr.isEmpty()) { + final Object[] all = list(); + for (int i = 0; i < all.length; i += 3) { + final String id = all[i].toString(); + Button b = createButton(id); + setText(b, all[i + 1].toString()); + if (Boolean.TRUE.equals(all[i + 2])) { + setEnabled(b, false); + } + arr.add(b); + } + if (arr.isEmpty()) { + Button ok = createButton("OK"); // NOI18N + setText(ok, Bundle.CTL_OK()); + arr.add(ok); + Button cancel = createButton(null); + setText(cancel, Bundle.CTL_Cancel()); + arr.add(cancel); } - btns.arr.add(b); - } - if (btns.arr.isEmpty()) { - JButton ok = new JButton(Bundle.CTL_OK()); - ok.setName("OK"); - btns.arr.add(ok); - btns.arr.add(new JButton(Bundle.CTL_Cancel())); } - return btns.arr.toArray(new JButton[0]); + return Collections.unmodifiableList(arr); } } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java index eb9a690ba28c..1ef8e6074188 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java @@ -25,6 +25,7 @@ import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; +import java.util.List; import javax.swing.JButton; import javax.swing.JComponent; import org.openide.*; @@ -33,8 +34,7 @@ final class HTMLDialogImpl extends HTMLDialogBase implements Runnable { private volatile int state; - private JComponent p; - private DialogDescriptor dd; + private ChromeWithButtons panel; private Object webView; private boolean nestedLoop; @@ -50,7 +50,7 @@ public void run() { break; case 1: state = 2; - webView = HtmlToolkit.getDefault().initHtmlDialog(url, dd, p, this, techIds); + webView = HtmlToolkit.getDefault().initHtmlDialog(url, panel.dd, panel.p, this, techIds); break; case 2: initPage(); @@ -75,6 +75,7 @@ public void run() { } } + @Override public String showAndWait() { if (EventQueue.isDispatchThread()) { run(); @@ -93,20 +94,14 @@ public String showAndWait() { showDialog(); } } - Object val = dd.getValue(); - return val instanceof JButton ? ((JButton)val).getName() : null; + return panel.getValueName(); } private void showDialog() { - p.setPreferredSize(new Dimension(600, 400)); - Dialog d = DialogDisplayer.getDefault().createDialog(dd); - d.setVisible(true); + panel.showDialog(); } private void initPanel() { - p = HtmlToolkit.getDefault().newPanel(); - dd = new DialogDescriptor(p, ""); - dd.setOptions(new Object[0]); state = 1; HtmlToolkit.getDefault().execute(this); } @@ -117,10 +112,10 @@ private void initPage() { } catch (Throwable t) { Exceptions.printStackTrace(t); } - final JButton[] buttons = Buttons.buttons(); - dd.setOptions(buttons); + panel.initButtons(); } + @Override public <C> C component(Class<C> type) { state = -1; ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class); @@ -135,4 +130,60 @@ public <C> C component(Class<C> type) { } return HtmlToolkit.getDefault().convertToComponent(type, pageUrl, loader, onPageLoad, techIds); } + + private static final class ChromeWithButtons extends Buttons<JButton> { + final JComponent p; + final DialogDescriptor dd; + + public ChromeWithButtons() { + this.p = HtmlToolkit.getDefault().newPanel(); + this.dd = new DialogDescriptor(p, ""); + this.dd.setOptions(new Object[0]); + } + + + + @Override + protected JButton createButton(String name) { + JButton b = new JButton(); + b.setName(name); + return b; + } + + @Override + protected String getName(JButton b) { + return b.getName(); + } + + @Override + protected void setText(JButton b, String text) { + b.setText(text); + } + + @Override + protected void setEnabled(JButton b, boolean enabled) { + b.setEnabled(enabled); + } + + @Override + protected void runLater(Runnable r) { + EventQueue.invokeLater(r); + } + + String getValueName() { + Object val = dd.getValue(); + return val instanceof JButton ? ((JButton)val).getName() : null; + } + + void showDialog() { + p.setPreferredSize(new Dimension(600, 400)); + Dialog d = DialogDisplayer.getDefault().createDialog(dd); + d.setVisible(true); + } + + void initButtons() { + List<JButton> buttons = buttons(); + dd.setOptions(buttons.toArray(new JButton[0])); + } + } } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java index c22576ba3b7a..9d86c14f3006 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java @@ -20,16 +20,19 @@ import java.net.MalformedURLException; import java.net.URL; -import java.util.Arrays; -import javax.swing.JButton; +import java.util.List; +import java.util.function.Consumer; +import net.java.html.js.JavaScriptBody; import org.openide.util.Exceptions; final class HTMLDialogView extends HTMLDialogBase { private final HtmlPair<?> view; + private final FooterButtons buttons; public HTMLDialogView(String url, HtmlPair<?> view) { super(url); this.view = view; + this.buttons = new FooterButtons(); } @Override @@ -38,15 +41,14 @@ public String showAndWait() { try { view.load(getClass().getClassLoader(), new URL(url), () -> { onPageLoad.run(); - JButton[] b = Buttons.buttons(); - System.err.println("butt: " + Arrays.toString(b)); + List<Object> b = buttons.buttons(); return null; }, this.techIds.toArray(new String[0])); } catch (MalformedURLException ex) { Exceptions.printStackTrace(ex); } }); - return null; + return this.buttons.obtainResult(); } @Override @@ -54,4 +56,65 @@ public <C> C component(Class<C> type) { return null; } + private final class FooterButtons extends Buttons<Object> implements Consumer<String> { + private static final String PREFIX = "dialog-buttons-"; + private String result; + + public synchronized String obtainResult() { + while (result == null) { + try { + wait(); + } catch (InterruptedException ex) { + // ignore + } + } + return result; + } + + @Override + public synchronized void accept(String t) { + if (t.startsWith(PREFIX)) { + result = t.substring(PREFIX.length()); + notifyAll(); + } + } + + @Override + protected Object createButton(String name) { + return view.createButton(PREFIX + name, this); + } + + @Override + protected String getName(Object b) { + String id = buttonName0(b); + if (id.startsWith(PREFIX)) { + return id.substring(PREFIX.length()); + } + return null; + } + + @Override + protected void setText(Object b, String text) { + buttonText0(b, text); + } + + @Override + protected void setEnabled(Object b, boolean enabled) { + buttonDisabled0(b, !enabled); + } + + @Override + protected void runLater(Runnable r) { + r.run(); + } + } + + @JavaScriptBody(args = { "b" }, body = "return b.id;") + native static String buttonName0(Object b); + + @JavaScriptBody(args = { "b", "text" }, body = "b.innerHTML = text;") + native static void buttonText0(Object b, String text); + + @JavaScriptBody(args = { "b", "disabled" }, body = "return b.disabled = disabled;") + native static String buttonDisabled0(Object b, boolean disabled); } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java index 78fe84900d46..5596717b1e14 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; +import java.util.function.Consumer; import java.util.logging.Level; import javax.swing.JComponent; import net.java.html.js.JavaScriptBody; @@ -156,5 +157,10 @@ public void makeVisible(HtmlComponent view, Runnable whenReady) { public void load(HtmlComponent view, ClassLoader loader, URL pageUrl, Callable<Object> initialize, String[] techIds) { view.loadFX(loader, pageUrl, initialize, techIds); } + + @Override + public Object createButton(String id, Consumer<String> run) { + return null; + } }; } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java index b8ee4993c0c8..83a23f7947dd 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java @@ -21,6 +21,7 @@ import org.netbeans.spi.htmlui.HtmlViewer; import java.net.URL; import java.util.concurrent.Callable; +import java.util.function.Consumer; import org.openide.util.Lookup; final class HtmlPair<HtmlView> { @@ -69,4 +70,8 @@ final void load(ClassLoader loader, URL pageUrl, Callable<Object> initialize, St final boolean isDefault() { return this.viewer == HtmlComponent.VIEWER; } + + Object createButton(String id, Consumer<String> callback) { + return viewer.createButton(id, callback); + } } diff --git a/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java b/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java index 57e329fca7f6..7a6e781032fb 100644 --- a/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java +++ b/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java @@ -20,6 +20,7 @@ import java.net.URL; import java.util.concurrent.Callable; +import java.util.function.Consumer; /** * @@ -30,4 +31,5 @@ public interface HtmlViewer<HtmlView> { public HtmlView newView(); public void makeVisible(HtmlView view, Runnable whenReady); public void load(HtmlView view, ClassLoader loader, URL pageUrl, Callable<Object> initialize, String[] techIds); + public Object createButton(String id, Consumer<String> callback); } From 7aec3fa291adc09f4a7214b2062e2495c992f950 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Wed, 24 Nov 2021 18:23:23 +0100 Subject: [PATCH 19/38] Notify back when a WebView is closed --- .../server/protocol/NbCodeClientWrapper.java | 6 ++--- .../server/protocol/NbCodeLanguageClient.java | 4 ++-- .../java/lsp/server/protocol/Server.java | 3 ++- .../server/protocol/WorkspaceUIContext.java | 4 ++-- .../ChangeMethodParametersRefactoring.java | 14 ----------- .../lsp/server/ui/AbstractLspHtmlViewer.java | 23 +++++++++++++++++-- .../modules/java/lsp/server/ui/UIContext.java | 6 +++-- .../lsp/server/TestCodeLanguageClient.java | 2 +- .../java/lsp/server/protocol/ServerTest.java | 13 ++--------- java/java.lsp.server/vscode/src/extension.ts | 15 ++++++++---- java/java.lsp.server/vscode/src/protocol.ts | 2 +- .../modules/htmlui/HTMLDialogView.java | 14 ++++++++--- 12 files changed, 58 insertions(+), 48 deletions(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java index 78de36ee1e30..31642fc40890 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java @@ -69,12 +69,10 @@ public void showStatusBarMessage(ShowStatusMessageParams params) { } @Override - public void showHtmlPage(HtmlPageParams params) { - remote.showHtmlPage(params); + public CompletableFuture<String> showHtmlPage(HtmlPageParams params) { + return remote.showHtmlPage(params); } - - @Override public CompletableFuture<List<QuickPickItem>> showQuickPick(ShowQuickPickParams params) { return remote.showQuickPick(params); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java index d9aeb798bd77..f2fabebe88a6 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java @@ -47,8 +47,8 @@ public interface NbCodeLanguageClient extends LanguageClient { * Shows an HTML based UI. * @param params the URI of the page to show */ - @JsonNotification("window/showHtmlPage") - public void showHtmlPage(@NonNull HtmlPageParams params); + @JsonRequest("window/showHtmlPage") + public CompletableFuture<String> showHtmlPage(@NonNull HtmlPageParams params); /** * Shows a selection list allowing multiple selections. diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java index f0cf12b3b3a9..43ee35c563bc 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java @@ -867,8 +867,9 @@ public void logMessage(MessageParams message) { } @Override - public void showHtmlPage(HtmlPageParams params) { + public CompletableFuture<String> showHtmlPage(HtmlPageParams params) { logWarning(params); + return CompletableFuture.completedFuture(null); } }; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java index 9d95d2a694f8..6bf76a3cf4f0 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java @@ -67,7 +67,7 @@ protected StatusDisplayer.Message showStatusMessage(ShowStatusMessageParams msg) } @Override - protected void showHtmlPage(HtmlPageParams msg) { - client.showHtmlPage(msg); + protected CompletableFuture<String> showHtmlPage(HtmlPageParams msg) { + return client.showHtmlPage(msg); } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java index 413c67e96639..011bb6b0c6ba 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -255,7 +255,6 @@ void doRefactoring(ChangeMethodParameterUI ui) { refactoring.setParameterInfo(params); refactoring.getContext().add(JavaRefactoringUtils.getClasspathInfoFor(file)); client.applyEdit(new ApplyWorkspaceEditParams(perform(refactoring, "ChangeMethodParameters"))); - closeWindow(); } catch (Exception ex) { client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); } @@ -293,19 +292,6 @@ void removeParameter(ChangeMethodParameterUI ui, ParameterUI data) { ui.getParameters().remove(data); } - @Function - void cancel(ChangeMethodParameterUI ui) { - closeWindow(); - } - - @JavaScriptBody(args = {}, body = "\n" - + "const vscode = acquireVsCodeApi();\n" // this method can be called only once per WebView existance - + "vscode.postMessage({\n" - + " command: 'dispose',\n" - + "});\n" - ) - private static native void closeWindow(); - @ComputedProperty static List<Modifier> availableModifiers() { return Arrays.asList(Modifier.values()); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java index 9484d000e863..b1577caaee19 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java @@ -46,16 +46,25 @@ public void makeVisible(View view, Runnable whenReady) { public void load(View view, ClassLoader loader, URL pageUrl, Callable<Object> initialize, String[] techIds) { UIContext ui = UIContext.find(); + AutoCloseable[] toClose = { null }; Browser.Config c = new Browser.Config(); c.browser((page) -> { try { - ui.showHtmlPage(new HtmlPageParams(page.toASCIIString())); + ui.showHtmlPage(new HtmlPageParams(page.toASCIIString())).thenAccept((t) -> { + try { + toClose[0].close(); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + }); } catch (Exception ex) { Exceptions.printStackTrace(ex); } }); - Fn.Presenter b = new Browser(c); + Browser b = new Browser(c); + toClose[0] = b; b.displayPage(pageUrl, () -> { + registerCloseWindow(); try { Object v = initialize.call(); System.err.println("v: " + v); @@ -65,6 +74,16 @@ public void load(View view, ClassLoader loader, URL pageUrl, Callable<Object> in }); } + @JavaScriptBody(args = {}, body = "\n" + + "const vscode = acquireVsCodeApi();\n" // this method can be called only once per WebView existance + + "window.close = function() {\n" + + " vscode.postMessage({\n" + + " command: 'dispose',\n" + + " });\n" + + "};\n" + ) + private static native void registerCloseWindow(); + @Override public Object createButton(String id, Consumer<String> callback) { return createButton0(id, callback); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java index 59a65864f754..a200627fab9f 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java @@ -78,8 +78,9 @@ public static synchronized UIContext find() { protected abstract boolean isValid(); protected abstract void showMessage(MessageParams msg); - protected void showHtmlPage(HtmlPageParams msg) { + protected CompletableFuture<String> showHtmlPage(HtmlPageParams msg) { showMessage(new MessageParams(MessageType.Log, msg.getUri())); + return CompletableFuture.completedFuture(null); } protected abstract CompletableFuture<MessageActionItem> showMessageRequest(ShowMessageRequestParams msg); protected abstract void logMessage(MessageParams msg); @@ -121,8 +122,9 @@ protected boolean isValid() { } @Override - protected void showHtmlPage(HtmlPageParams msg) { + protected CompletableFuture<String> showHtmlPage(HtmlPageParams msg) { System.out.println("Open in browser: " + msg.getUri()); + return CompletableFuture.completedFuture(null); } } } diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java index 9166d2a1869b..b601a62acee9 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java @@ -42,7 +42,7 @@ public void showStatusBarMessage(ShowStatusMessageParams params) { } @Override - public void showHtmlPage(HtmlPageParams params) { + public CompletableFuture<String> showHtmlPage(HtmlPageParams params) { throw new UnsupportedOperationException(); } diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java index 28c12c65deee..e0bd058eb7b3 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java @@ -4737,11 +4737,6 @@ public CompletableFuture<List<QuickPickItem>> showQuickPick(ShowQuickPickParams public void showStatusBarMessage(ShowStatusMessageParams params) { throw new UnsupportedOperationException(); } - - @Override - public void showHtmlPage(HtmlPageParams params) { - throw new UnsupportedOperationException(); - } }, client.getInputStream(), client.getOutputStream()); serverLauncher.startListening(); LanguageServer server = serverLauncher.getRemoteProxy(); @@ -4885,11 +4880,6 @@ public CompletableFuture<List<QuickPickItem>> showQuickPick(ShowQuickPickParams public void showStatusBarMessage(ShowStatusMessageParams params) { throw new UnsupportedOperationException(); } - - @Override - public void showHtmlPage(HtmlPageParams params) { - throw new UnsupportedOperationException(); - } }, client.getInputStream(), client.getOutputStream()); serverLauncher.startListening(); LanguageServer server = serverLauncher.getRemoteProxy(); @@ -5048,9 +5038,10 @@ public void showStatusBarMessage(ShowStatusMessageParams params) { } @Override - public void showHtmlPage(HtmlPageParams params) { + public CompletableFuture<String> showHtmlPage(HtmlPageParams params) { ChangeMethodParameterUI ui = MockHtmlViewer.assertDialogShown(params.getUri(), ChangeMethodParameterUI.class); ui.doRefactoring(); + return CompletableFuture.completedFuture(null); } }, client.getInputStream(), client.getOutputStream()); serverLauncher.startListening(); diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index 8991cd93f400..de7aa4b51de1 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -609,7 +609,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex c.onReady().then(() => { testAdapter = new NbTestAdapter(); c.onNotification(StatusMessageRequest.type, showStatusBarMessage); - c.onNotification(HtmlPageRequest.type, showHtmlPage); + c.onRequest(HtmlPageRequest.type, showHtmlPage); c.onNotification(LogMessageNotification.type, (param) => handleLog(log, param.message)); c.onRequest(QuickPickRequest.type, async param => { const selected = await window.showQuickPick(param.items, { placeHolder: param.placeHolder, canPickMany: param.canPickMany }); @@ -676,8 +676,8 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex window.showErrorMessage('Error initializing ' + reason); }); - function showHtmlPage(params : HtmlPageParams) { - function showUri(url: string) { + async function showHtmlPage(params : HtmlPageParams): Promise<string> { + function showUri(url: string, ok: any, err: any) { let uri = vscode.Uri.parse(url); var http = require('http'); @@ -708,14 +708,19 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex break; } }); + view.onDidDispose(() => { + ok(null); + }); }); }); request.on('error', function(e: any) { - vscode.window.showWarningMessage(e.message); + err(e); }); request.end(); } - showUri(params.uri); + return new Promise((ok, err) => { + showUri(params.uri, ok, err); + }); } function showStatusBarMessage(params : ShowStatusMessageParams) { diff --git a/java/java.lsp.server/vscode/src/protocol.ts b/java/java.lsp.server/vscode/src/protocol.ts index 570794d1e90b..574ecb2a1c4e 100644 --- a/java/java.lsp.server/vscode/src/protocol.ts +++ b/java/java.lsp.server/vscode/src/protocol.ts @@ -42,7 +42,7 @@ export interface HtmlPageParams { } export namespace HtmlPageRequest { - export const type = new NotificationType<HtmlPageParams>('window/showHtmlPage'); + export const type = new ProtocolRequestType<HtmlPageParams, string, never, void, void>('window/showHtmlPage'); }; export namespace StatusMessageRequest { diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java index 9d86c14f3006..d4795bd58ee0 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java @@ -58,10 +58,11 @@ public <C> C component(Class<C> type) { private final class FooterButtons extends Buttons<Object> implements Consumer<String> { private static final String PREFIX = "dialog-buttons-"; + private boolean hasResult; private String result; public synchronized String obtainResult() { - while (result == null) { + while (!hasResult) { try { wait(); } catch (InterruptedException ex) { @@ -73,10 +74,14 @@ public synchronized String obtainResult() { @Override public synchronized void accept(String t) { - if (t.startsWith(PREFIX)) { + if (t == null) { + result = null; + } else if (t.startsWith(PREFIX)) { result = t.substring(PREFIX.length()); - notifyAll(); } + hasResult = true; + notifyAll(); + closeWindow0(); } @Override @@ -117,4 +122,7 @@ protected void runLater(Runnable r) { @JavaScriptBody(args = { "b", "disabled" }, body = "return b.disabled = disabled;") native static String buttonDisabled0(Object b, boolean disabled); + + @JavaScriptBody(args = {}, body = "window.close();") + native static void closeWindow0(); } From 560daf248e4e90be955c0913c13517bc0bb91f53 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Thu, 25 Nov 2021 08:38:53 +0100 Subject: [PATCH 20/38] Associated lifecycle callback with each HTML view/dialog --- .../lsp/server/ui/AbstractLspHtmlViewer.java | 98 ++++++++++++------- .../org/netbeans/modules/htmlui/Buttons.java | 1 - .../modules/htmlui/HTMLDialogBase.java | 10 +- .../modules/htmlui/HTMLDialogImpl.java | 4 + .../modules/htmlui/HTMLDialogView.java | 8 ++ .../modules/htmlui/HtmlComponent.java | 4 +- .../org/netbeans/modules/htmlui/HtmlPair.java | 12 +-- .../org/netbeans/modules/htmlui/Pages.java | 9 +- .../org/netbeans/spi/htmlui/HtmlViewer.java | 4 +- 9 files changed, 100 insertions(+), 50 deletions(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java index b1577caaee19..ba456ea80a81 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java @@ -22,7 +22,6 @@ import java.util.concurrent.Callable; import java.util.function.Consumer; import net.java.html.js.JavaScriptBody; -import org.netbeans.html.boot.spi.Fn; import org.netbeans.modules.java.lsp.server.htmlui.Browser; import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams; import org.netbeans.spi.htmlui.HtmlViewer; @@ -33,8 +32,9 @@ protected AbstractLspHtmlViewer() { } @Override - public View newView() { - return new View(); + public View newView(Consumer<String> lifeCycleCallback) { + UIContext ui = UIContext.find(); + return new View(ui, lifeCycleCallback); } @Override @@ -44,34 +44,7 @@ public void makeVisible(View view, Runnable whenReady) { @Override public void load(View view, ClassLoader loader, URL pageUrl, Callable<Object> initialize, String[] techIds) { - UIContext ui = UIContext.find(); - - AutoCloseable[] toClose = { null }; - Browser.Config c = new Browser.Config(); - c.browser((page) -> { - try { - ui.showHtmlPage(new HtmlPageParams(page.toASCIIString())).thenAccept((t) -> { - try { - toClose[0].close(); - } catch (Exception ex) { - throw new IllegalStateException(ex); - } - }); - } catch (Exception ex) { - Exceptions.printStackTrace(ex); - } - }); - Browser b = new Browser(c); - toClose[0] = b; - b.displayPage(pageUrl, () -> { - registerCloseWindow(); - try { - Object v = initialize.call(); - System.err.println("v: " + v); - } catch (Exception ex) { - Exceptions.printStackTrace(ex); - } - }); + view.load(pageUrl, initialize); } @JavaScriptBody(args = {}, body = "\n" @@ -85,8 +58,8 @@ public void load(View view, ClassLoader loader, URL pageUrl, Callable<Object> in private static native void registerCloseWindow(); @Override - public Object createButton(String id, Consumer<String> callback) { - return createButton0(id, callback); + public Object createButton(View view, String id) { + return createButton0(id, view.callback); } @JavaScriptBody(args = { "id", "callback" }, javacall = true, body = "\n" @@ -115,8 +88,63 @@ public Object createButton(String id, Consumer<String> callback) { ) native static Object createButton0(String id, Consumer<?> callback); - public static final class View { - public View() { + static final class View { + private final Consumer<String> callback; + private final UIContext ui; + private Browser presenter; + + private View(UIContext ui, Consumer<String> callback) { + this.ui = ui; + this.callback = callback; + } + + private void notifyClose() { + if (callback != null) { + callback.accept(null); + } + } + + private void load(URL pageUrl, Callable<?> initialize) { + Browser.Config c = new Browser.Config(); + c.browser((page) -> { + try { + ui.showHtmlPage(new HtmlPageParams(page.toASCIIString())).thenAccept((t) -> { + final Browser p = presenter; + if (p == null) { + return; + } + try { + notifyClose(); + } catch (Throwable ex) { + Exceptions.printStackTrace(ex); + } + try { + p.close(); + } catch (Exception ex) { + Exceptions.printStackTrace(ex); + } finally { + presenter = null; + } + }).exceptionally((t) -> { + notifyClose(); + presenter = null; + return null; + }); + } catch (Exception ex) { + Exceptions.printStackTrace(ex); + } + }); + presenter = new Browser(c); + presenter.displayPage(pageUrl, () -> { + registerCloseWindow(); + try { + Object v = initialize.call(); + System.err.println("v: " + v); + } catch (Exception ex) { + Exceptions.printStackTrace(ex); + } + }); + } } } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java index 91fc79a58076..6fea85dba511 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.function.Consumer; import net.java.html.js.JavaScriptBody; import org.openide.util.NbBundle; diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java index 89d52a196196..6b2c3a8f2cba 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java @@ -34,6 +34,7 @@ public abstract class HTMLDialogBase { public abstract String showAndWait(); public abstract <C> C component(Class<C> type); + protected abstract void onSubmit(String id); public void addTechIds(String[] ids) { this.techIds.addAll(Arrays.asList(ids)); @@ -44,7 +45,12 @@ public void setOnPageLoad(Runnable onPageLoad) { } public static HTMLDialogBase create(String url) { - HtmlPair<?> view = HtmlPair.newView(); - return view.isDefault() ? new HTMLDialogImpl(url) : new HTMLDialogView(url, view); + HTMLDialogBase[] base = { null }; + HtmlPair<?> view = HtmlPair.newView((id) -> { + base[0].onSubmit(id); + }); + final HTMLDialogBase dialog = view.isDefault() ? new HTMLDialogImpl(url) : new HTMLDialogView(url, view); + base[0] = dialog; + return dialog; } } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java index 1ef8e6074188..e576392f9a37 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java @@ -97,6 +97,10 @@ public String showAndWait() { return panel.getValueName(); } + @Override + protected void onSubmit(String id) { + } + private void showDialog() { panel.showDialog(); } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java index d4795bd58ee0..a535d710e2de 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java @@ -55,6 +55,11 @@ public String showAndWait() { public <C> C component(Class<C> type) { return null; } + + @Override + protected void onSubmit(String id) { + this.buttons.accept(id); + } private final class FooterButtons extends Buttons<Object> implements Consumer<String> { private static final String PREFIX = "dialog-buttons-"; @@ -74,6 +79,9 @@ public synchronized String obtainResult() { @Override public synchronized void accept(String t) { + if (hasResult) { + return; + } if (t == null) { result = null; } else if (t.startsWith(PREFIX)) { diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java index 5596717b1e14..4db6ce6a65ec 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlComponent.java @@ -142,7 +142,7 @@ final void onChange(Object[] values) { static final HtmlViewer<?> VIEWER = new HtmlViewer<HtmlComponent>() { @Override - public HtmlComponent newView() { + public HtmlComponent newView(Consumer<String> lifeCycleCallback) { return new HtmlComponent(); } @@ -159,7 +159,7 @@ public void load(HtmlComponent view, ClassLoader loader, URL pageUrl, Callable<O } @Override - public Object createButton(String id, Consumer<String> run) { + public Object createButton(HtmlComponent view, String id) { return null; } }; diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java index 83a23f7947dd..d301a36dc82b 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HtmlPair.java @@ -44,18 +44,18 @@ static Class<?> loadClass(String c) throws ClassNotFoundException { return Class.forName(c, true, l); } - static HtmlPair<?> newView() { + static HtmlPair<?> newView(Consumer<String> life) { for (HtmlViewer<?> viewer : Lookup.getDefault().lookupAll(HtmlViewer.class)) { - HtmlPair<?> pair = newView(viewer); + HtmlPair<?> pair = newView(viewer, life); if (pair != null) { return pair; } } - return newView(HtmlComponent.VIEWER); + return newView(HtmlComponent.VIEWER, life); } - private static <HtmlView> HtmlPair<HtmlView> newView(HtmlViewer<HtmlView> viewer) { - final HtmlView view = viewer.newView(); + private static <HtmlView> HtmlPair<HtmlView> newView(HtmlViewer<HtmlView> viewer, Consumer<String> life) { + final HtmlView view = viewer.newView(life); return view == null ? null : new HtmlPair<>(viewer, view); } @@ -72,6 +72,6 @@ final boolean isDefault() { } Object createButton(String id, Consumer<String> callback) { - return viewer.createButton(id, callback); + return viewer.createButton(view, id); } } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Pages.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Pages.java index a29b39774211..7cdd2cbf4185 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Pages.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Pages.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import javax.swing.Action; import org.openide.awt.Actions; import org.openide.util.Lookup; @@ -47,7 +48,7 @@ public static Action openAction(final Map<?,?> map) { ); } - static class R implements ActionListener, Runnable { + static class R implements ActionListener, Runnable, Consumer<String> { private final Map<?,?> map; private String methodName; private Class<?> clazz; @@ -69,7 +70,7 @@ public void actionPerformed(ActionEvent e) { clazz = HtmlPair.loadClass(c); pageUrl = new URL("nbresloc:/" + u); - tc = HtmlPair.newView(); + tc = HtmlPair.newView(this); tc.makeVisible(this); } catch (Exception ex) { throw new IllegalStateException(ex); @@ -104,5 +105,9 @@ final String[] getTechIds() { } return techIds.toArray(new String[0]); } + + @Override + public void accept(String t) { + } } } diff --git a/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java b/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java index 7a6e781032fb..7006dc7e0bed 100644 --- a/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java +++ b/platform/api.htmlui/src/org/netbeans/spi/htmlui/HtmlViewer.java @@ -28,8 +28,8 @@ * @since 1.21 */ public interface HtmlViewer<HtmlView> { - public HtmlView newView(); + public HtmlView newView(Consumer<String> lifeCycleCallback); public void makeVisible(HtmlView view, Runnable whenReady); public void load(HtmlView view, ClassLoader loader, URL pageUrl, Callable<Object> initialize, String[] techIds); - public Object createButton(String id, Consumer<String> callback); + public Object createButton(HtmlView view, String id); } From 2961f0a88452ca90f4016d1ed67c8d5d236f0ed0 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Thu, 25 Nov 2021 09:54:29 +0100 Subject: [PATCH 21/38] Refactoring/Change Method Parameters Refactoring action to demonstrate the refactoring UI also works in NetBeans --- .../ChangeMethodParametersRefactoring.java | 12 ++- ...angeMethodParametersRefactoringAction.java | 84 ++++++++++++++++++ .../java/lsp/server/refactoring/newHTML.png | Bin 0 -> 819 bytes .../modules/htmlui/HTMLDialogImpl.java | 3 +- 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/newHTML.png diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java index 011bb6b0c6ba..3927e483dd17 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; +import java.util.logging.Level; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.VariableElement; @@ -61,6 +62,7 @@ import org.netbeans.modules.refactoring.java.api.ChangeParametersRefactoring; import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; import org.openide.filesystems.FileObject; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; import org.openide.util.lookup.ServiceProvider; @@ -256,7 +258,13 @@ void doRefactoring(ChangeMethodParameterUI ui) { refactoring.getContext().add(JavaRefactoringUtils.getClasspathInfoFor(file)); client.applyEdit(new ApplyWorkspaceEditParams(perform(refactoring, "ChangeMethodParameters"))); } catch (Exception ex) { - client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + if (client == null) { + Exceptions.printStackTrace( + Exceptions.attachSeverity(ex, Level.SEVERE) + ); + } else { + client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + } } } @@ -333,7 +341,7 @@ void getInfo(ParameterUI model, int idx, BiConsumer<Integer, ChangeParametersRef } } - static enum Modifier { + public static enum Modifier { PUBLIC("public"), PROTECTED("protected"), PACKAGE_PRIVATE("", "package private"), PRIVATE("private"); final String javaName; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java new file mode 100644 index 000000000000..ba48aa66f522 --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.java.lsp.server.refactoring; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.JavaSource; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionRegistration; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle.Messages; + +@ActionID( + category = "Refactoring", + id = "org.netbeans.modules.java.lsp.server.refactoring.ChangeMethodParametersRefactoringAction" +) +@ActionRegistration( + iconBase = "org/netbeans/modules/java/lsp/server/refactoring/newHTML.png", + displayName = "#CTL_ChangeMethodParametersRefactoringAction" +) +@ActionReference(path = "Menu/Refactoring", position = 1120) +@Messages("CTL_ChangeMethodParametersRefactoringAction=Change Method Parameters Refactoring") +public final class ChangeMethodParametersRefactoringAction implements ActionListener { + private final FileObject file; + + public ChangeMethodParametersRefactoringAction(FileObject file) { + this.file = file; + } + + @Override + public void actionPerformed(ActionEvent evt) { + JavaSource js = JavaSource.forFileObject(file); + if (js != null) { + try { + js.runUserActionTask(ci -> { + ci.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); + ExecutableElement method = null; + METHOD: for (Element type : ci.getTopLevelElements()) { + for (Element e : type.getEnclosedElements()) { + System.err.println("e: " + e); + if (e.getKind() == ElementKind.METHOD) { + method = (ExecutableElement) e; + break METHOD; + } + } + } + if (method != null) { + ElementHandle<ExecutableElement> handle = ElementHandle.create(method); + ChangeMethodParameterUI[] model = {null}; + String res = Pages.showChangeMethodParametersUI(ci, null, file, handle, method, model); + if ("accept".equals(res)) { + model[0].doRefactoring(); + } + } + }, true); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + } +} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/newHTML.png b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/newHTML.png new file mode 100644 index 0000000000000000000000000000000000000000..608de64f86ceeb69a50c53b80357d8443f33453e GIT binary patch literal 819 zcmV-31I+x1P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0008|Nkl<Zc-oay z3rJI86rQ0L6iw5*Hr@4ZZaTf2Q*WY0(KIbbR+>#k%~zph+C+1PL|I}HDPsAEB=7-) zG_+Qzh*|_{6h=XzC{tn1oSXM%)}6z-)6^akX!ZRZ`1#NIzw_XH490KR{ILIrL?W>j z3WW%U`8oVcJXjOKnq)R2ROHBU=NF)C>;@0z;lBclaeF#3$Zamck8g+*dQ;K3Sbv<m z=gSGt18_R<AY|d&RtN|#!Ngp#3N{NhAt=_%<nY6n9aMZUHXr9(^ZBTIw>}hkK}uNz zRE+CeQ=-QRl_YvU5-s#zZ2`l!xU;!=&bwGfw;c$eyU`B}7Z)kydpc85UVU?lc+lUw z4s$Klu+-ZGmew+;JGl?e26+ds)=Cg|4leApFpd}5j0)k|W)_67JU;pa3S*~3kv6iq z7IcICR+3^cKP-i*@(eh$-yi&aJf%O|wR3UWnOZ7|(0>YxfpJ?Ws7uL&+{;&W4I+ne z!=0if-9Qh_l;y%=%Pla}=7U@kK!*qf1jBmlT&?2|IV`QI%#wfWk;<SWBL^nb<1nVt z(j6&My*BfRS=ap-^bc-=v8w@KupNfZONZN|gdPlhJHCU<=BDRf$SWTn9i5+<odt@f zVHswtO(|<Yle8CfeO)k9RRna~U4U1QVCiDSAS4qg!_AE=;<)qPDHNCbDT-SCxdscb zpMy3w0H$x}fnL=J#`gOF6-hv+`45sZ9A)_9xY)-FS5;S4zcCt(mOlv=C)F^mh+on~ zaLBJwT#`=YQ40xzk+}rlVp2vhS0<RAoz3d(Y=3I8Sio#HgLYDDQmfVTBuTB1P?`x- zSz=5hMDt|SDc@vGj30mPX4=SPGE}Klc8;mXK=nj5T2fM4rcfyI>+2g@hlhse^@dqU zJ(t_K-fG)ewcsGnkrxye7B)pjMjo@iEth6b5CnSdN=ad5W#!B8L*aQF>0^^XAaLSv xIEeLbyVijq$X2mf?1?f_$G?eeBRQ|@`wkyMe{?LNQFs6V002ovPDHLkV1nR2b+7;c literal 0 HcmV?d00001 diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java index e576392f9a37..bf9889f875cd 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java @@ -34,12 +34,13 @@ final class HTMLDialogImpl extends HTMLDialogBase implements Runnable { private volatile int state; - private ChromeWithButtons panel; + private final ChromeWithButtons panel; private Object webView; private boolean nestedLoop; HTMLDialogImpl(String url) { super(url); + this.panel = new ChromeWithButtons(); } @Override From 7b53b632de5886904cdfa908b0e5f6713e4642ee Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Sun, 5 Dec 2021 07:22:28 +0100 Subject: [PATCH 22/38] Testing HTML/Java API 1.7.3 --- .../antsrc/org/netbeans/nbbuild/extlibs/DownloadBinaries.java | 2 +- nbbuild/binaries-default-properties.xml | 2 +- platform/generic/external/binaries-list | 2 +- .../{generic-1.7.2-license.txt => generic-1.7.3-license.txt} | 2 +- platform/generic/nbproject/project.properties | 2 +- platform/generic/nbproject/project.xml | 2 +- platform/net.java.html.boot.fx/external/binaries-list | 2 +- ....7.2-license.txt => net.java.html.boot.fx-1.7.3-license.txt} | 2 +- platform/net.java.html.boot.fx/nbproject/project.properties | 2 +- platform/net.java.html.boot.fx/nbproject/project.xml | 2 +- platform/net.java.html.boot.script/external/binaries-list | 2 +- ...-license.txt => net.java.html.boot.script-1.7.3-license.txt} | 2 +- platform/net.java.html.boot.script/nbproject/project.properties | 2 +- platform/net.java.html.boot.script/nbproject/project.xml | 2 +- platform/net.java.html.boot/external/binaries-list | 2 +- ...t-1.7.2-license.txt => net.java.html.boot-1.7.3-license.txt} | 2 +- platform/net.java.html.boot/nbproject/project.properties | 2 +- platform/net.java.html.boot/nbproject/project.xml | 2 +- platform/net.java.html.geo/external/binaries-list | 2 +- ...eo-1.7.2-license.txt => net.java.html.geo-1.7.3-license.txt} | 2 +- platform/net.java.html.geo/nbproject/project.properties | 2 +- platform/net.java.html.geo/nbproject/project.xml | 2 +- platform/net.java.html.json/external/binaries-list | 2 +- ...n-1.7.2-license.txt => net.java.html.json-1.7.3-license.txt} | 2 +- platform/net.java.html.json/nbproject/project.properties | 2 +- platform/net.java.html.json/nbproject/project.xml | 2 +- platform/net.java.html.sound/external/binaries-list | 2 +- ...-1.7.2-license.txt => net.java.html.sound-1.7.3-license.txt} | 2 +- platform/net.java.html.sound/nbproject/project.properties | 2 +- platform/net.java.html.sound/nbproject/project.xml | 2 +- platform/net.java.html/external/binaries-list | 2 +- ...a.html-1.7.2-license.txt => net.java.html-1.7.3-license.txt} | 2 +- platform/net.java.html/nbproject/project.properties | 2 +- platform/net.java.html/nbproject/project.xml | 2 +- platform/o.n.html.ko4j/external/binaries-list | 2 +- .../external/{ko4j-1.7.2-license.txt => ko4j-1.7.3-license.txt} | 2 +- platform/o.n.html.ko4j/nbproject/project.properties | 2 +- platform/o.n.html.ko4j/nbproject/project.xml | 2 +- platform/o.n.html.xhr4j/external/binaries-list | 2 +- .../{xhr4j-1.7.2-license.txt => xhr4j-1.7.3-license.txt} | 2 +- platform/o.n.html.xhr4j/nbproject/project.properties | 2 +- platform/o.n.html.xhr4j/nbproject/project.xml | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) rename platform/generic/external/{generic-1.7.2-license.txt => generic-1.7.3-license.txt} (99%) rename platform/net.java.html.boot.fx/external/{net.java.html.boot.fx-1.7.2-license.txt => net.java.html.boot.fx-1.7.3-license.txt} (99%) rename platform/net.java.html.boot.script/external/{net.java.html.boot.script-1.7.2-license.txt => net.java.html.boot.script-1.7.3-license.txt} (99%) rename platform/net.java.html.boot/external/{net.java.html.boot-1.7.2-license.txt => net.java.html.boot-1.7.3-license.txt} (99%) rename platform/net.java.html.geo/external/{net.java.html.geo-1.7.2-license.txt => net.java.html.geo-1.7.3-license.txt} (99%) rename platform/net.java.html.json/external/{net.java.html.json-1.7.2-license.txt => net.java.html.json-1.7.3-license.txt} (99%) rename platform/net.java.html.sound/external/{net.java.html.sound-1.7.2-license.txt => net.java.html.sound-1.7.3-license.txt} (99%) rename platform/net.java.html/external/{net.java.html-1.7.2-license.txt => net.java.html-1.7.3-license.txt} (99%) rename platform/o.n.html.ko4j/external/{ko4j-1.7.2-license.txt => ko4j-1.7.3-license.txt} (99%) rename platform/o.n.html.xhr4j/external/{xhr4j-1.7.2-license.txt => xhr4j-1.7.3-license.txt} (99%) diff --git a/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/DownloadBinaries.java b/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/DownloadBinaries.java index bb1b352833fb..f42e729b81f2 100644 --- a/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/DownloadBinaries.java +++ b/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/DownloadBinaries.java @@ -61,7 +61,7 @@ * Motivation: http://wiki.netbeans.org/wiki/view/HgMigration#section-HgMigration-Binaries */ public class DownloadBinaries extends Task { - private static final String MAVEN_REPO = "https://repo1.maven.org/maven2/"; + private static final String MAVEN_REPO = "https://repo1.maven.org/maven2/ https://repository.apache.org/content/repositories/orgapachenetbeans-1093/"; private static final Pattern URL_PATTERN = Pattern.compile("(https?://\\S*[^/\\s]+)\\s+(\\S+)$"); diff --git a/nbbuild/binaries-default-properties.xml b/nbbuild/binaries-default-properties.xml index 6bc9ea5c032e..bee39395d595 100644 --- a/nbbuild/binaries-default-properties.xml +++ b/nbbuild/binaries-default-properties.xml @@ -22,5 +22,5 @@ <project name="binaries-default-properties" default="netbeans" basedir="."> <property name="binaries.cache" location="${user.home}/.hgexternalcache"/> <property name="binaries.server" value="https://netbeans.osuosl.org/binaries/"/> - <property name="binaries.repos" value="https://repo1.maven.org/maven2/"/> + <property name="binaries.repos" value="https://repo1.maven.org/maven2/ https://repository.apache.org/content/repositories/orgapachenetbeans-1093/"/> </project> diff --git a/platform/generic/external/binaries-list b/platform/generic/external/binaries-list index eb826dc566bc..a2968acd383f 100644 --- a/platform/generic/external/binaries-list +++ b/platform/generic/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -1CF79022EC9B51258719250B31A55F0E1F2F7F76 org.netbeans.html:generic:1.7.2 +7621B0AFE4260212C6632FE74E6F5CCDBB61EEB8 org.netbeans.html:generic:1.7.3 diff --git a/platform/generic/external/generic-1.7.2-license.txt b/platform/generic/external/generic-1.7.3-license.txt similarity index 99% rename from platform/generic/external/generic-1.7.2-license.txt rename to platform/generic/external/generic-1.7.3-license.txt index f09f029d17d9..d136fb3d98cc 100644 --- a/platform/generic/external/generic-1.7.2-license.txt +++ b/platform/generic/external/generic-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: Knockout4J -Version: 1.7.2 +Version: 1.7.3 Description: Knockout4J License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/generic/nbproject/project.properties b/platform/generic/nbproject/project.properties index 53f597ef2f83..e52ed8853057 100644 --- a/platform/generic/nbproject/project.properties +++ b/platform/generic/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/generic-1.7.2.jar=modules/generic.jar +release.external/generic-1.7.3.jar=modules/generic.jar nbm.module.author=Jaroslav Tulach is.autoload=true diff --git a/platform/generic/nbproject/project.xml b/platform/generic/nbproject/project.xml index 837baf84f887..a352e4faea68 100644 --- a/platform/generic/nbproject/project.xml +++ b/platform/generic/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>generic.jar</runtime-relative-path> - <binary-origin>external/generic-1.7.2.jar</binary-origin> + <binary-origin>external/generic-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> diff --git a/platform/net.java.html.boot.fx/external/binaries-list b/platform/net.java.html.boot.fx/external/binaries-list index ad28b379a0e1..75db770f1ea7 100644 --- a/platform/net.java.html.boot.fx/external/binaries-list +++ b/platform/net.java.html.boot.fx/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -C6C7E7F406BCC131A79BD6A1C2B32F47F6E881B9 org.netbeans.html:net.java.html.boot.fx:1.7.2 +10F1724D618C0F0BA57D0CB849A0C6463A8C3F03 org.netbeans.html:net.java.html.boot.fx:1.7.3 diff --git a/platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7.2-license.txt b/platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7.3-license.txt similarity index 99% rename from platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7.2-license.txt rename to platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7.3-license.txt index dc8df7ecf551..76cb5d13c449 100644 --- a/platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7.2-license.txt +++ b/platform/net.java.html.boot.fx/external/net.java.html.boot.fx-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: Html4J -Version: 1.7.2 +Version: 1.7.3 Description: Html4j Boot FX License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.boot.fx/nbproject/project.properties b/platform/net.java.html.boot.fx/nbproject/project.properties index 85e71724b9f7..4eaf3930d996 100644 --- a/platform/net.java.html.boot.fx/nbproject/project.properties +++ b/platform/net.java.html.boot.fx/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.boot.fx-1.7.2.jar=modules/net-java-html-boot-fx.jar +release.external/net.java.html.boot.fx-1.7.3.jar=modules/net-java-html-boot-fx.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.boot.fx/nbproject/project.xml b/platform/net.java.html.boot.fx/nbproject/project.xml index 92d341e9883d..efebe1f6c8af 100644 --- a/platform/net.java.html.boot.fx/nbproject/project.xml +++ b/platform/net.java.html.boot.fx/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>net-java-html-boot-fx.jar</runtime-relative-path> - <binary-origin>external/net.java.html.boot.fx-1.7.2.jar</binary-origin> + <binary-origin>external/net.java.html.boot.fx-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> diff --git a/platform/net.java.html.boot.script/external/binaries-list b/platform/net.java.html.boot.script/external/binaries-list index e87454cfbe5e..1c9a9ff8c084 100644 --- a/platform/net.java.html.boot.script/external/binaries-list +++ b/platform/net.java.html.boot.script/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -620D43EF251C93A69AA2142A25CFF80351EDDF3B org.netbeans.html:net.java.html.boot.script:1.7.2 +30B5376222E678298714053EDEA38AD13AEF1DB8 org.netbeans.html:net.java.html.boot.script:1.7.3 diff --git a/platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7.2-license.txt b/platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7.3-license.txt similarity index 99% rename from platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7.2-license.txt rename to platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7.3-license.txt index 9abf0bb5b184..cb1a4f8d9828 100644 --- a/platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7.2-license.txt +++ b/platform/net.java.html.boot.script/external/net.java.html.boot.script-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: Html4J -Version: 1.7.2 +Version: 1.7.3 Description: Html4j Boot Script License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.boot.script/nbproject/project.properties b/platform/net.java.html.boot.script/nbproject/project.properties index 6e301da6150d..ed6576acc951 100644 --- a/platform/net.java.html.boot.script/nbproject/project.properties +++ b/platform/net.java.html.boot.script/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.boot.script-1.7.2.jar=modules/net-java-html-boot-script.jar +release.external/net.java.html.boot.script-1.7.3.jar=modules/net-java-html-boot-script.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.boot.script/nbproject/project.xml b/platform/net.java.html.boot.script/nbproject/project.xml index d227dfc45ff9..398605b5fcc2 100644 --- a/platform/net.java.html.boot.script/nbproject/project.xml +++ b/platform/net.java.html.boot.script/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>net-java-html-boot-script.jar</runtime-relative-path> - <binary-origin>external/net.java.html.boot.script-1.7.2.jar</binary-origin> + <binary-origin>external/net.java.html.boot.script-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> diff --git a/platform/net.java.html.boot/external/binaries-list b/platform/net.java.html.boot/external/binaries-list index 62b7981672ab..6864fdee2de1 100644 --- a/platform/net.java.html.boot/external/binaries-list +++ b/platform/net.java.html.boot/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -97032FDEFB37E38D4483A08EE1C8908DAB628467 org.netbeans.html:net.java.html.boot:1.7.2 +F4320C98E15B3DB8C6F7468FF23B1CA929087471 org.netbeans.html:net.java.html.boot:1.7.3 diff --git a/platform/net.java.html.boot/external/net.java.html.boot-1.7.2-license.txt b/platform/net.java.html.boot/external/net.java.html.boot-1.7.3-license.txt similarity index 99% rename from platform/net.java.html.boot/external/net.java.html.boot-1.7.2-license.txt rename to platform/net.java.html.boot/external/net.java.html.boot-1.7.3-license.txt index 9ad527cffcc3..dbc1573f29fc 100644 --- a/platform/net.java.html.boot/external/net.java.html.boot-1.7.2-license.txt +++ b/platform/net.java.html.boot/external/net.java.html.boot-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: Html4J -Version: 1.7.2 +Version: 1.7.3 Description: Html4j Boot License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.boot/nbproject/project.properties b/platform/net.java.html.boot/nbproject/project.properties index 798d7dab7451..0d7e770527e2 100644 --- a/platform/net.java.html.boot/nbproject/project.properties +++ b/platform/net.java.html.boot/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.boot-1.7.2.jar=modules/net-java-html-boot.jar +release.external/net.java.html.boot-1.7.3.jar=modules/net-java-html-boot.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.boot/nbproject/project.xml b/platform/net.java.html.boot/nbproject/project.xml index 4efb265675bc..a8222f32fbdd 100644 --- a/platform/net.java.html.boot/nbproject/project.xml +++ b/platform/net.java.html.boot/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>net-java-html-boot.jar</runtime-relative-path> - <binary-origin>external/net.java.html.boot-1.7.2.jar</binary-origin> + <binary-origin>external/net.java.html.boot-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> diff --git a/platform/net.java.html.geo/external/binaries-list b/platform/net.java.html.geo/external/binaries-list index e3135fbe9ed2..d457c6728303 100644 --- a/platform/net.java.html.geo/external/binaries-list +++ b/platform/net.java.html.geo/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -536E44A4FA6E1AF1B92795C5B7EDFB68A3680427 org.netbeans.html:net.java.html.geo:1.7.2 +7AE5571DACE8CAD67E894A1EAB92F0B295587992 org.netbeans.html:net.java.html.geo:1.7.3 diff --git a/platform/net.java.html.geo/external/net.java.html.geo-1.7.2-license.txt b/platform/net.java.html.geo/external/net.java.html.geo-1.7.3-license.txt similarity index 99% rename from platform/net.java.html.geo/external/net.java.html.geo-1.7.2-license.txt rename to platform/net.java.html.geo/external/net.java.html.geo-1.7.3-license.txt index 79f23f8cc074..549582c0d533 100644 --- a/platform/net.java.html.geo/external/net.java.html.geo-1.7.2-license.txt +++ b/platform/net.java.html.geo/external/net.java.html.geo-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: Html4J Geolocation API -Version: 1.7.2 +Version: 1.7.3 Description: Html4j Geolocation API License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.geo/nbproject/project.properties b/platform/net.java.html.geo/nbproject/project.properties index e8aee4ff2039..1141f732e126 100644 --- a/platform/net.java.html.geo/nbproject/project.properties +++ b/platform/net.java.html.geo/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.geo-1.7.2.jar=modules/net-java-html-geo.jar +release.external/net.java.html.geo-1.7.3.jar=modules/net-java-html-geo.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.geo/nbproject/project.xml b/platform/net.java.html.geo/nbproject/project.xml index 5b3e3ad64e04..412ad4896e47 100644 --- a/platform/net.java.html.geo/nbproject/project.xml +++ b/platform/net.java.html.geo/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>net-java-html-geo.jar</runtime-relative-path> - <binary-origin>external/net.java.html.geo-1.7.2.jar</binary-origin> + <binary-origin>external/net.java.html.geo-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> diff --git a/platform/net.java.html.json/external/binaries-list b/platform/net.java.html.json/external/binaries-list index d7014919159e..a385952a4a0f 100644 --- a/platform/net.java.html.json/external/binaries-list +++ b/platform/net.java.html.json/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -B801FD4A689F1443A108E79BBEA24893EB8F2935 org.netbeans.html:net.java.html.json:1.7.2 +F52F8CFEA7C7A74CB9DB31BB12B4FF4075A94811 org.netbeans.html:net.java.html.json:1.7.3 diff --git a/platform/net.java.html.json/external/net.java.html.json-1.7.2-license.txt b/platform/net.java.html.json/external/net.java.html.json-1.7.3-license.txt similarity index 99% rename from platform/net.java.html.json/external/net.java.html.json-1.7.2-license.txt rename to platform/net.java.html.json/external/net.java.html.json-1.7.3-license.txt index bda3b88ae5b7..9066601d2925 100644 --- a/platform/net.java.html.json/external/net.java.html.json-1.7.2-license.txt +++ b/platform/net.java.html.json/external/net.java.html.json-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: Html4J JSON Model in Java -Version: 1.7.2 +Version: 1.7.3 Description: Html4j JSON Model in Java License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.json/nbproject/project.properties b/platform/net.java.html.json/nbproject/project.properties index 6db4c3ee853e..e313fd912090 100644 --- a/platform/net.java.html.json/nbproject/project.properties +++ b/platform/net.java.html.json/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.json-1.7.2.jar=modules/net-java-html-json.jar +release.external/net.java.html.json-1.7.3.jar=modules/net-java-html-json.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.json/nbproject/project.xml b/platform/net.java.html.json/nbproject/project.xml index 526fa5d6da2d..83e912c8dc36 100644 --- a/platform/net.java.html.json/nbproject/project.xml +++ b/platform/net.java.html.json/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>net-java-html-json.jar</runtime-relative-path> - <binary-origin>external/net.java.html.json-1.7.2.jar</binary-origin> + <binary-origin>external/net.java.html.json-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> diff --git a/platform/net.java.html.sound/external/binaries-list b/platform/net.java.html.sound/external/binaries-list index 26b939277a08..c26f9dc7a313 100644 --- a/platform/net.java.html.sound/external/binaries-list +++ b/platform/net.java.html.sound/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -A6B3198F8987B4486EE62601DF212840FC9D3B41 org.netbeans.html:net.java.html.sound:1.7.2 +AFBA69B9F15BC582FC0D888C1154C52D45557DFF org.netbeans.html:net.java.html.sound:1.7.3 diff --git a/platform/net.java.html.sound/external/net.java.html.sound-1.7.2-license.txt b/platform/net.java.html.sound/external/net.java.html.sound-1.7.3-license.txt similarity index 99% rename from platform/net.java.html.sound/external/net.java.html.sound-1.7.2-license.txt rename to platform/net.java.html.sound/external/net.java.html.sound-1.7.3-license.txt index c569638d26dd..45351b508b19 100644 --- a/platform/net.java.html.sound/external/net.java.html.sound-1.7.2-license.txt +++ b/platform/net.java.html.sound/external/net.java.html.sound-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: Html4J Sound API via HTML -Version: 1.7.2 +Version: 1.7.3 Description: Html4j Sound API via HTML License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html.sound/nbproject/project.properties b/platform/net.java.html.sound/nbproject/project.properties index f2cdb1c42cc3..7063616ac500 100644 --- a/platform/net.java.html.sound/nbproject/project.properties +++ b/platform/net.java.html.sound/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html.sound-1.7.2.jar=modules/net-java-html-sound.jar +release.external/net.java.html.sound-1.7.3.jar=modules/net-java-html-sound.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html.sound/nbproject/project.xml b/platform/net.java.html.sound/nbproject/project.xml index 2015c8f75cd2..4f614c6caaca 100644 --- a/platform/net.java.html.sound/nbproject/project.xml +++ b/platform/net.java.html.sound/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>net-java-html-sound.jar</runtime-relative-path> - <binary-origin>external/net.java.html.sound-1.7.2.jar</binary-origin> + <binary-origin>external/net.java.html.sound-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> diff --git a/platform/net.java.html/external/binaries-list b/platform/net.java.html/external/binaries-list index 8bc1decc3ca3..5eecc12aaa01 100644 --- a/platform/net.java.html/external/binaries-list +++ b/platform/net.java.html/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -FD957A7BD4652EED5F4E982B186CAB036BA2DBBE org.netbeans.html:net.java.html:1.7.2 +8D34C9BF1D1A898E5E6A618B220DB3FC00C2F936 org.netbeans.html:net.java.html:1.7.3 diff --git a/platform/net.java.html/external/net.java.html-1.7.2-license.txt b/platform/net.java.html/external/net.java.html-1.7.3-license.txt similarity index 99% rename from platform/net.java.html/external/net.java.html-1.7.2-license.txt rename to platform/net.java.html/external/net.java.html-1.7.3-license.txt index c443c03d3a67..20b4bd0a75c3 100644 --- a/platform/net.java.html/external/net.java.html-1.7.2-license.txt +++ b/platform/net.java.html/external/net.java.html-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: Html4J -Version: 1.7.2 +Version: 1.7.3 Description: Html4j License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/net.java.html/nbproject/project.properties b/platform/net.java.html/nbproject/project.properties index 53d7f24863a8..ceffa53aa57e 100644 --- a/platform/net.java.html/nbproject/project.properties +++ b/platform/net.java.html/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/net.java.html-1.7.2.jar=modules/net-java-html.jar +release.external/net.java.html-1.7.3.jar=modules/net-java-html.jar is.autoload=true nbm.module.author=Jaroslav Tulach diff --git a/platform/net.java.html/nbproject/project.xml b/platform/net.java.html/nbproject/project.xml index fd8ddd0ac387..b2490eb8b49f 100644 --- a/platform/net.java.html/nbproject/project.xml +++ b/platform/net.java.html/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>net-java-html.jar</runtime-relative-path> - <binary-origin>external/net.java.html-1.7.2.jar</binary-origin> + <binary-origin>external/net.java.html-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> diff --git a/platform/o.n.html.ko4j/external/binaries-list b/platform/o.n.html.ko4j/external/binaries-list index f89b1d52c873..1950c13bf6ba 100644 --- a/platform/o.n.html.ko4j/external/binaries-list +++ b/platform/o.n.html.ko4j/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -87D636A969271FD9207959D17AA64ADA68523774 org.netbeans.html:ko4j:1.7.2 +F63214CFA9BDFCBD48E3A0BDEEEF379999AB4AD2 org.netbeans.html:ko4j:1.7.3 diff --git a/platform/o.n.html.ko4j/external/ko4j-1.7.2-license.txt b/platform/o.n.html.ko4j/external/ko4j-1.7.3-license.txt similarity index 99% rename from platform/o.n.html.ko4j/external/ko4j-1.7.2-license.txt rename to platform/o.n.html.ko4j/external/ko4j-1.7.3-license.txt index f09f029d17d9..d136fb3d98cc 100644 --- a/platform/o.n.html.ko4j/external/ko4j-1.7.2-license.txt +++ b/platform/o.n.html.ko4j/external/ko4j-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: Knockout4J -Version: 1.7.2 +Version: 1.7.3 Description: Knockout4J License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/o.n.html.ko4j/nbproject/project.properties b/platform/o.n.html.ko4j/nbproject/project.properties index a766d53d3fe1..951cccc68134 100644 --- a/platform/o.n.html.ko4j/nbproject/project.properties +++ b/platform/o.n.html.ko4j/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/ko4j-1.7.2.jar=modules/org-netbeans-html-ko4j.jar +release.external/ko4j-1.7.3.jar=modules/org-netbeans-html-ko4j.jar nbm.module.author=Jaroslav Tulach is.autoload=true diff --git a/platform/o.n.html.ko4j/nbproject/project.xml b/platform/o.n.html.ko4j/nbproject/project.xml index c5a909fdf450..7138aa83c13e 100644 --- a/platform/o.n.html.ko4j/nbproject/project.xml +++ b/platform/o.n.html.ko4j/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>org-netbeans-html-ko4j.jar</runtime-relative-path> - <binary-origin>external/ko4j-1.7.2.jar</binary-origin> + <binary-origin>external/ko4j-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> diff --git a/platform/o.n.html.xhr4j/external/binaries-list b/platform/o.n.html.xhr4j/external/binaries-list index c0102f9a8d6f..e62f628ff4ef 100644 --- a/platform/o.n.html.xhr4j/external/binaries-list +++ b/platform/o.n.html.xhr4j/external/binaries-list @@ -14,4 +14,4 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -9EB95313E0BA7AE774B5FB25C5429EF2DEEB2B5A org.netbeans.html:xhr4j:1.7.2 +2756D001008576536B68C1B43D96053E82723D65 org.netbeans.html:xhr4j:1.7.3 diff --git a/platform/o.n.html.xhr4j/external/xhr4j-1.7.2-license.txt b/platform/o.n.html.xhr4j/external/xhr4j-1.7.3-license.txt similarity index 99% rename from platform/o.n.html.xhr4j/external/xhr4j-1.7.2-license.txt rename to platform/o.n.html.xhr4j/external/xhr4j-1.7.3-license.txt index a926af524cfa..534c1e8d11ec 100644 --- a/platform/o.n.html.xhr4j/external/xhr4j-1.7.2-license.txt +++ b/platform/o.n.html.xhr4j/external/xhr4j-1.7.3-license.txt @@ -1,5 +1,5 @@ Name: XHR via Java -Version: 1.7.2 +Version: 1.7.3 Description: XHR via Java License: Apache-2.0 Origin: Apache Software Foundation diff --git a/platform/o.n.html.xhr4j/nbproject/project.properties b/platform/o.n.html.xhr4j/nbproject/project.properties index 5cfe84c9ab33..2e125b716be4 100644 --- a/platform/o.n.html.xhr4j/nbproject/project.properties +++ b/platform/o.n.html.xhr4j/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/xhr4j-1.7.2.jar=modules/org-netbeans-html-xhr4j.jar +release.external/xhr4j-1.7.3.jar=modules/org-netbeans-html-xhr4j.jar nbm.module.author=Jaroslav Tulach is.autoload=true diff --git a/platform/o.n.html.xhr4j/nbproject/project.xml b/platform/o.n.html.xhr4j/nbproject/project.xml index cb53b90f2649..c1a875a04993 100644 --- a/platform/o.n.html.xhr4j/nbproject/project.xml +++ b/platform/o.n.html.xhr4j/nbproject/project.xml @@ -28,7 +28,7 @@ <public-packages/> <class-path-extension> <runtime-relative-path>org-netbeans-html-xhr4j.jar</runtime-relative-path> - <binary-origin>external/xhr4j-1.7.2.jar</binary-origin> + <binary-origin>external/xhr4j-1.7.3.jar</binary-origin> </class-path-extension> </data> </configuration> From 31baffd384832ac82e45ebc0327af9bef1abdbc6 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Sun, 5 Dec 2021 14:22:07 +0100 Subject: [PATCH 23/38] Adjusting the test to Buttons being instantiable --- .../netbeans/modules/htmlui/DialogsTest.java | 74 ++++++++++++++----- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java index 1c3ec63c7231..7e7571f93ee0 100644 --- a/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java +++ b/platform/htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogsTest.java @@ -91,22 +91,24 @@ public void run() { " <button hidden=true id='OK' disabled=true>Agree</button>" + " <button hidden=true id='Cancel'>Disagree</button>"; setBody(body); - - JButton[] arr = Buttons.buttons(); + + + + JButton[] arr = new MockButtons().array(); assertEquals(arr.length, 2, "Two buttons"); assertEquals(arr[0].getName(), "OK", "id of 1st button parsed"); assertEquals(arr[1].getName(), "Cancel", "id of 2nd button parsed"); assertEquals(arr[0].getText(), "Agree", "text of 1st button parsed"); assertEquals(arr[1].getText(), "Disagree", "text of 2nd button parsed"); - + assertFalse(arr[0].isEnabled(), "OK is disabled"); assertTrue(arr[1].isEnabled(), "Cancel is enabled"); - + setDisabled("OK", false); - + String prev = setText("OK", "Fine"); assertEquals(prev, "Agree"); - + buttons[0] = arr[0]; buttons[1] = arr[1]; } catch (Throwable t) { @@ -128,7 +130,7 @@ public void run() { } }); } - + @Test(timeOut = 9000) public void noDefinedButtonsMeanOKCancel() throws Throwable { EnsureJavaFXPresent.checkAndThrow(); @@ -140,17 +142,17 @@ public void run() { try { String body = " <button>Normal button in a text</button>" + -// no dialog buttons defined: +// no dialog buttons defined: // " <button hidden=true id='OK' disabled=true>Agree</button>" + // " <button hidden=true id='Cancel'>Disagree</button>" + ""; setBody(body); - - JButton[] arr = Buttons.buttons(); + + JButton[] arr = new MockButtons().array(); assertEquals(arr.length, 2, "Two buttons"); assertEquals(arr[0].getName(), "OK", "id of 1st default button"); assertEquals(arr[1].getName(), null, "id of 2nd default button"); - + assertTrue(arr[0].isEnabled(), "OK is enabled"); assertTrue(arr[1].isEnabled(), "Cancel is enabled"); } catch (Throwable t) { @@ -165,29 +167,65 @@ public void run() { throw ex[0]; } } - + @JavaScriptBody(args = "b", body = "window.document.getElementsByTagName('body')[0].innerHTML = b;") private static native void setBody(String b); - + @JavaScriptBody(args = { "id", "state" }, body = "window.document.getElementById(id).disabled = state;") private static native void setDisabled(String id, boolean state); - + @JavaScriptBody(args = { "id", "t" }, body = "" + "var prev = window.document.getElementById(id).innerHTML;\n" + "window.document.getElementById(id).innerHTML = t;\n" + "return prev;\n" ) private static native String setText(String id, String t); - - - @HTMLDialog(url = "simple.html", className = "TestPages") + + + @HTMLDialog(url = "simple.html", className = "TestPages") static void showDialog() { String ret = TestPages.showDialog(); } - @HTMLDialog(url = "http://www.netbeans.org", className = "TestPages") + @HTMLDialog(url = "http://www.netbeans.org", className = "TestPages") static void showDialog(int x, String[] y, DialogsTest t) { String ret = TestPages.showDialog(10, y, null); } + + private static class MockButtons extends Buttons<JButton> { + MockButtons() { + } + + @Override + protected JButton createButton(String name) { + JButton b = new JButton(); + b.setName(name); + return b; + } + + @Override + protected String getName(JButton b) { + return b.getName(); + } + + @Override + protected void setText(JButton b, String text) { + b.setText(text); + } + + @Override + protected void setEnabled(JButton b, boolean enabled) { + b.setEnabled(enabled); + } + + @Override + protected void runLater(Runnable r) { + r.run(); + } + + final JButton[] array() { + return buttons().toArray(new JButton[0]); + } + } } From 26a7e325a13067425c895c95f62023ec3c261ea4 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Sun, 5 Dec 2021 15:24:45 +0100 Subject: [PATCH 24/38] Using new fully qualified name of org.netbeans.html.presenters.spi OSGi bundle --- .../nbcode/integration/nbproject/project.xml | 4 ++-- java/java.lsp.server/nbproject/project.xml | 6 +++--- nbbuild/cluster.properties | 2 +- platform/{generic => o.n.html.presenters.spi}/build.xml | 2 +- .../external/binaries-list | 0 .../external/generic-1.7.3-license.txt | 0 platform/{generic => o.n.html.presenters.spi}/manifest.mf | 0 .../nbproject/project.properties | 2 +- .../nbproject/project.xml | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) rename platform/{generic => o.n.html.presenters.spi}/build.xml (92%) rename platform/{generic => o.n.html.presenters.spi}/external/binaries-list (100%) rename platform/{generic => o.n.html.presenters.spi}/external/generic-1.7.3-license.txt (100%) rename platform/{generic => o.n.html.presenters.spi}/manifest.mf (100%) rename platform/{generic => o.n.html.presenters.spi}/nbproject/project.properties (91%) rename platform/{generic => o.n.html.presenters.spi}/nbproject/project.xml (88%) diff --git a/java/java.lsp.server/nbcode/integration/nbproject/project.xml b/java/java.lsp.server/nbcode/integration/nbproject/project.xml index 6a39e6cab853..920381d12337 100644 --- a/java/java.lsp.server/nbcode/integration/nbproject/project.xml +++ b/java/java.lsp.server/nbcode/integration/nbproject/project.xml @@ -69,11 +69,11 @@ </run-dependency> </dependency> <dependency> - <code-name-base>generic</code-name-base> + <code-name-base>org.netbeans.html.presenters.spi</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> - <specification-version>1.7.2</specification-version> + <specification-version>1.7.3</specification-version> </run-dependency> </dependency> <dependency> diff --git a/java/java.lsp.server/nbproject/project.xml b/java/java.lsp.server/nbproject/project.xml index 94a2a00e1d1b..7db7e0c2ed4f 100644 --- a/java/java.lsp.server/nbproject/project.xml +++ b/java/java.lsp.server/nbproject/project.xml @@ -85,15 +85,15 @@ <build-prerequisite/> <compile-dependency/> <run-dependency> - <specification-version>1.7.2</specification-version> + <specification-version>1.7.3</specification-version> </run-dependency> </dependency> <dependency> - <code-name-base>generic</code-name-base> + <code-name-base>org.netbeans.html.presenters.spi</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> - <specification-version>1.7.2</specification-version> + <specification-version>1.7.3</specification-version> </run-dependency> </dependency> <dependency> diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties index 8ac993c722f6..0120da02fca4 100644 --- a/nbbuild/cluster.properties +++ b/nbbuild/cluster.properties @@ -226,7 +226,6 @@ nb.cluster.platform=\ editor.mimelookup,\ editor.mimelookup.impl,\ favorites,\ - generic,\ htmlui,\ janitor,\ javahelp,\ @@ -265,6 +264,7 @@ nb.cluster.platform=\ o.apache.commons.logging,\ o.n.core,\ o.n.html.ko4j,\ + o.n.html.presenters.spi,\ o.n.html.xhr4j,\ o.n.swing.laf.dark,\ o.n.swing.laf.flatlaf,\ diff --git a/platform/generic/build.xml b/platform/o.n.html.presenters.spi/build.xml similarity index 92% rename from platform/generic/build.xml rename to platform/o.n.html.presenters.spi/build.xml index 28e98611a16b..04b9362828fc 100644 --- a/platform/generic/build.xml +++ b/platform/o.n.html.presenters.spi/build.xml @@ -19,7 +19,7 @@ under the License. --> -<project name="platform/generic" default="build" basedir="."> +<project name="platform/o.n.html.presenters.spi" default="build" basedir="."> <import file="../../nbbuild/templates/projectized.xml"/> <target name="jar"/> </project> diff --git a/platform/generic/external/binaries-list b/platform/o.n.html.presenters.spi/external/binaries-list similarity index 100% rename from platform/generic/external/binaries-list rename to platform/o.n.html.presenters.spi/external/binaries-list diff --git a/platform/generic/external/generic-1.7.3-license.txt b/platform/o.n.html.presenters.spi/external/generic-1.7.3-license.txt similarity index 100% rename from platform/generic/external/generic-1.7.3-license.txt rename to platform/o.n.html.presenters.spi/external/generic-1.7.3-license.txt diff --git a/platform/generic/manifest.mf b/platform/o.n.html.presenters.spi/manifest.mf similarity index 100% rename from platform/generic/manifest.mf rename to platform/o.n.html.presenters.spi/manifest.mf diff --git a/platform/generic/nbproject/project.properties b/platform/o.n.html.presenters.spi/nbproject/project.properties similarity index 91% rename from platform/generic/nbproject/project.properties rename to platform/o.n.html.presenters.spi/nbproject/project.properties index e52ed8853057..6a152d3766c8 100644 --- a/platform/generic/nbproject/project.properties +++ b/platform/o.n.html.presenters.spi/nbproject/project.properties @@ -14,6 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -release.external/generic-1.7.3.jar=modules/generic.jar +release.external/generic-1.7.3.jar=modules/org-netbeans-html-presenters-spi.jar nbm.module.author=Jaroslav Tulach is.autoload=true diff --git a/platform/generic/nbproject/project.xml b/platform/o.n.html.presenters.spi/nbproject/project.xml similarity index 88% rename from platform/generic/nbproject/project.xml rename to platform/o.n.html.presenters.spi/nbproject/project.xml index a352e4faea68..c3d09afc33c1 100644 --- a/platform/generic/nbproject/project.xml +++ b/platform/o.n.html.presenters.spi/nbproject/project.xml @@ -23,11 +23,11 @@ <type>org.netbeans.modules.apisupport.project</type> <configuration> <data xmlns="http://www.netbeans.org/ns/nb-module-project/2"> - <code-name-base>generic</code-name-base> + <code-name-base>org.netbeans.html.presenters.spi</code-name-base> <module-dependencies/> <public-packages/> <class-path-extension> - <runtime-relative-path>generic.jar</runtime-relative-path> + <runtime-relative-path>org-netbeans-html-presenters-spi.jar</runtime-relative-path> <binary-origin>external/generic-1.7.3.jar</binary-origin> </class-path-extension> </data> From 1f8a5cfdd8c6e71b9185956784bea3135af781d2 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Mon, 6 Dec 2021 10:06:20 +0100 Subject: [PATCH 25/38] OnSubmit callback to validate non-blocking dialog --- .../src/org/netbeans/junit/MockServices.java | 9 +- .../ChangeMethodParametersRefactoring.java | 21 ++-- ...angeMethodParametersRefactoringAction.java | 6 +- platform/api.htmlui/manifest.mf | 2 +- platform/api.htmlui/nbproject/project.xml | 14 ++- .../org/netbeans/api/htmlui/HTMLDialog.java | 29 ++++- .../modules/htmlui/HTMLDialogBase.java | 2 + .../modules/htmlui/HTMLDialogImpl.java | 23 ++++ .../modules/htmlui/HTMLDialogProcessor.java | 92 +++++++++++----- .../modules/htmlui/HTMLDialogView.java | 33 ++++-- .../modules/htmlui/DialogOnSubmitTest.java | 71 +++++++++++++ .../modules/htmlui/MockHtmlViewer.java | 100 ++++++++++++++++++ platform/htmlui/nbproject/project.xml | 2 +- 13 files changed, 342 insertions(+), 62 deletions(-) create mode 100644 platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogOnSubmitTest.java create mode 100644 platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/MockHtmlViewer.java diff --git a/harness/nbjunit/src/org/netbeans/junit/MockServices.java b/harness/nbjunit/src/org/netbeans/junit/MockServices.java index c450ae552032..08f9cf053d92 100644 --- a/harness/nbjunit/src/org/netbeans/junit/MockServices.java +++ b/harness/nbjunit/src/org/netbeans/junit/MockServices.java @@ -37,8 +37,6 @@ import java.util.NoSuchElementException; import java.util.logging.Level; import java.util.logging.Logger; -import junit.framework.Assert; -import junit.framework.AssertionFailedError; /** * Lets you register mock implementations of global services. @@ -161,7 +159,10 @@ public ServiceClassLoader(Class<?>[] services, ClassLoader l, boolean test) { for (Class<?> c : services) { try { if (test) { - Assert.assertEquals(c, getParent().loadClass(c.getName())); + final Class<?> real = getParent().loadClass(c.getName()); + if (!c.equals(real)) { + throw new AssertionError("Service " + c + " isn't " + real); + } } int mods = c.getModifiers(); if (!Modifier.isPublic(mods) || Modifier.isAbstract(mods)) { @@ -173,7 +174,7 @@ public ServiceClassLoader(Class<?>[] services, ClassLoader l, boolean test) { } catch (NoSuchMethodException x) { throw (IllegalArgumentException) new IllegalArgumentException("Class " + c.getName() + " has no public no-arg constructor").initCause(x); } catch (Exception x) { - throw (AssertionFailedError) new AssertionFailedError(x.toString()).initCause(x); + throw new AssertionError(x.toString(), x); } } this.services = services; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java index a0fa8368e793..627a9611e766 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -34,7 +34,6 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; -import net.java.html.js.JavaScriptBody; import net.java.html.json.ComputedProperty; import net.java.html.json.Function; import net.java.html.json.Model; @@ -142,11 +141,7 @@ public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, Str ci.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); ExecutableElement method = (ExecutableElement) handle.resolve(ci); if (method != null) { - ChangeMethodParameterUI[] model = { null }; - String res = Pages.showChangeMethodParametersUI(ci, client, file, handle, method, model); - if ("accept".equals(res)) { - model[0].doRefactoring(); - } + Pages.showChangeMethodParametersUI(ci, client, file, handle, method); } }, true); return null; @@ -181,13 +176,12 @@ private static String defaultValue(String type) { } @HTMLDialog(url = "ui/ChangeMethodParameters.html") - static ChangeMethodParameterUI showChangeMethodParametersUI( + static HTMLDialog.OnSubmit showChangeMethodParametersUI( CompilationController ci, NbCodeLanguageClient client, FileObject file, ElementHandle handle, - ExecutableElement method, - ChangeMethodParameterUI[] modelBack + ExecutableElement method ) { ParameterUI[] params = new ParameterUI[method.getParameters().size()]; for (int i = 0; i < method.getParameters().size(); i++) { @@ -212,8 +206,13 @@ static ChangeMethodParameterUI showChangeMethodParametersUI( .withSelectedModifier(mod) .withParameters(params) .assignData(client, file, TreePathHandle.from(handle, ClasspathInfo.create(file))); - modelBack[0] = model; - return model.applyBindings(); + model.applyBindings(); + return (id) -> { + if ("accept".equals(id)) { + model.doRefactoring(); + } + return true; // return false, if validation fails + }; } @Model(className = "ChangeMethodParameterUI", targetId = "", instance = true, builder = "with", properties = { diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java index ba48aa66f522..82b65358a005 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java @@ -69,11 +69,7 @@ public void actionPerformed(ActionEvent evt) { } if (method != null) { ElementHandle<ExecutableElement> handle = ElementHandle.create(method); - ChangeMethodParameterUI[] model = {null}; - String res = Pages.showChangeMethodParametersUI(ci, null, file, handle, method, model); - if ("accept".equals(res)) { - model[0].doRefactoring(); - } + Pages.showChangeMethodParametersUI(ci, null, file, handle, method); } }, true); } catch (IOException ex) { diff --git a/platform/api.htmlui/manifest.mf b/platform/api.htmlui/manifest.mf index 42543cedb61e..6e5cfe9a5774 100644 --- a/platform/api.htmlui/manifest.mf +++ b/platform/api.htmlui/manifest.mf @@ -1,4 +1,4 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.api.htmlui OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/htmlui/Bundle.properties -OpenIDE-Module-Specification-Version: 1.22 +OpenIDE-Module-Specification-Version: 1.23 diff --git a/platform/api.htmlui/nbproject/project.xml b/platform/api.htmlui/nbproject/project.xml index 18d338aa619d..97b476725509 100644 --- a/platform/api.htmlui/nbproject/project.xml +++ b/platform/api.htmlui/nbproject/project.xml @@ -80,7 +80,7 @@ </run-dependency> </dependency> <dependency> - <code-name-base>org.openide.util.ui</code-name-base> + <code-name-base>org.openide.util</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> @@ -88,19 +88,19 @@ </run-dependency> </dependency> <dependency> - <code-name-base>org.openide.util</code-name-base> + <code-name-base>org.openide.util.lookup</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> - <specification-version>9.3</specification-version> + <specification-version>8.25</specification-version> </run-dependency> </dependency> <dependency> - <code-name-base>org.openide.util.lookup</code-name-base> + <code-name-base>org.openide.util.ui</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> - <specification-version>8.25</specification-version> + <specification-version>9.3</specification-version> </run-dependency> </dependency> <dependency> @@ -128,6 +128,10 @@ <code-name-base>org.netbeans.libs.testng</code-name-base> <compile-dependency/> </test-dependency> + <test-dependency> + <code-name-base>org.netbeans.modules.nbjunit</code-name-base> + <compile-dependency/> + </test-dependency> </test-type> </test-dependencies> <public-packages> diff --git a/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java b/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java index f0f49ec90d1b..f016bbf8c37e 100644 --- a/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java +++ b/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java @@ -24,6 +24,7 @@ import java.lang.annotation.Target; import java.util.Locale; import java.awt.event.ActionEvent; +import java.util.concurrent.Callable; import net.java.html.json.Model; import net.java.html.json.Property; import org.netbeans.html.context.spi.Contexts.Id; @@ -126,6 +127,22 @@ */ String[] techIds() default {}; + /** + * + * @since 1.23 + */ + @FunctionalInterface + public interface OnSubmit { + /** Callback when a button is pressed. + * + * @param button the ID of the pressed button or {@code null} on cancel + * @return {@code true} to close the dialog, {@code false} to ignore + * the button press and leave the dialog open + * @since 1.23 + */ + boolean onSubmit(String button); + } + /** Rather than using this class directly, consider * {@link HTMLDialog}. The {@link HTMLDialog} annotation * generates boilderplate code for you @@ -175,7 +192,7 @@ public Builder addTechIds(String... ids) { return this; } - /** Displays the dialog. This method blocks waiting for the + /** Displays the dialog and waits. This method blocks waiting for the * dialog to be shown and closed by the user. * * @return 'id' of a selected button element or <code>null</code> @@ -185,6 +202,16 @@ public String showAndWait() { return impl.showAndWait(); } + /** Displays the dialog and returns immediately. + * + * @param s callback to call when a button is clicked and dialog + * is about to be closed + * @since 1.23 + */ + public void show(OnSubmit s) { + impl.show(s); + } + /** Obtains the component from the builder. The parameter * can either be {@link javafx.embed.swing.JFXPanel}.<b>class</b> or * {@link javafx.scene.web.WebView}.<b>class</b>. After calling this diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java index 6b2c3a8f2cba..a18367de340f 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogBase.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.netbeans.api.htmlui.HTMLDialog; public abstract class HTMLDialogBase { List<String> techIds = new ArrayList<>(); @@ -33,6 +34,7 @@ public abstract class HTMLDialogBase { public abstract String showAndWait(); + public abstract void show(HTMLDialog.OnSubmit onSubmit); public abstract <C> C component(Class<C> type); protected abstract void onSubmit(String id); diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java index bf9889f875cd..607359b1c816 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java @@ -28,6 +28,7 @@ import java.util.List; import javax.swing.JButton; import javax.swing.JComponent; +import org.netbeans.api.htmlui.HTMLDialog; import org.openide.*; import org.openide.util.Exceptions; import org.openide.util.Lookup; @@ -98,6 +99,28 @@ public String showAndWait() { return panel.getValueName(); } + @Override + public void show(HTMLDialog.OnSubmit onSubmit) { + if (EventQueue.isDispatchThread()) { + run(); + showDialog(); + } else { + if (HtmlToolkit.getDefault().isApplicationThread()) { + nestedLoop = true; + EventQueue.invokeLater(this); + HtmlToolkit.getDefault().enterNestedLoop(this); + } else { + try { + EventQueue.invokeAndWait(this); + } catch (InterruptedException | InvocationTargetException ex) { + throw new IllegalStateException(ex); + } + showDialog(); + } + } + panel.getValueName(); + } + @Override protected void onSubmit(String id) { } diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogProcessor.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogProcessor.java index ce7ef0607007..88c285400ffc 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogProcessor.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogProcessor.java @@ -42,6 +42,8 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.MirroredTypeException; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; import javax.tools.FileObject; import javax.tools.JavaFileManager; @@ -72,14 +74,14 @@ public Set<String> getSupportedAnnotationTypes() { public SourceVersion getSupportedSourceVersion() { return SourceVersion.latest(); } - + private Set<Element> annotatedWith(RoundEnvironment re, Class<? extends Annotation> type) { Set<Element> collect = new HashSet<>(); findAllElements(re.getElementsAnnotatedWith(type), collect, type); return collect; } - - + + @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment re) { Map<String,Set<ExecutableElement>> names = new TreeMap<>(); @@ -98,11 +100,11 @@ public boolean process(Set<? extends TypeElement> set, RoundEnvironment re) { if (!ee.getThrownTypes().isEmpty()) { error("Method annotated by @HTMLDialog cannot throw exceptions", e); } - + PackageElement pkg = findPkg(ee); - + String fqn = pkg.getQualifiedName() + "." + reg.className(); - + Set<ExecutableElement> elems = names.get(fqn); if (elems == null) { elems = new TreeSet<>(this); @@ -125,11 +127,11 @@ public boolean process(Set<? extends TypeElement> set, RoundEnvironment re) { if (!ee.getThrownTypes().isEmpty()) { error("Method annotated by @HTMLComponent cannot throw exceptions", e); } - + PackageElement pkg = findPkg(ee); - + String fqn = pkg.getQualifiedName() + "." + reg.className(); - + Set<ExecutableElement> elems = names.get(fqn); if (elems == null) { elems = new TreeSet<>(this); @@ -137,7 +139,7 @@ public boolean process(Set<? extends TypeElement> set, RoundEnvironment re) { } elems.add(ee); } - + for (Map.Entry<String, Set<ExecutableElement>> entry : names.entrySet()) { String clazzName = entry.getKey(); Set<ExecutableElement> elems = entry.getValue(); @@ -155,7 +157,7 @@ public boolean process(Set<? extends TypeElement> set, RoundEnvironment re) { w.append("class ").append(arr[1]).append(" {\n"); w.append(" private ").append(arr[1]).append("() {\n }\n"); w.append("\n"); - + for (ExecutableElement ee : elems) { HTMLDialog reg = ee.getAnnotation(HTMLDialog.class); HTMLComponent comp = ee.getAnnotation(HTMLComponent.class); @@ -186,15 +188,15 @@ public boolean process(Set<? extends TypeElement> set, RoundEnvironment re) { generateComponent(w, ee, t, url, comp.techIds()); } } - + w.append("}\n"); w.close(); - + } catch (IOException ex) { error("Cannot create " + clazzName, first); } } - + return true; } @@ -217,7 +219,16 @@ private String findURL(final String relativeURL, ExecutableElement ee) { } private void generateDialog(Writer w, ExecutableElement ee, String url, String[] techIds) throws IOException { - w.append(" public static String ").append(ee.getSimpleName()); + TypeElement onSubmit = processingEnv.getElementUtils().getTypeElement(HTMLDialog.OnSubmit.class.getCanonicalName()); + final TypeMirror retType = ee.getReturnType(); + boolean returnsOnSubmit = retType.getKind() != TypeKind.ERROR && processingEnv.getTypeUtils().isSubtype(retType, onSubmit.asType()); + w.append(" public static "); + if (returnsOnSubmit) { + w.append("void "); + } else { + w.append("String "); + } + w.append(ee.getSimpleName()); w.append("("); String sep = ""; for (VariableElement v : ee.getParameters()) { @@ -225,13 +236,27 @@ private void generateDialog(Writer w, ExecutableElement ee, String url, String[] w.append("final ").append(v.asType().toString()).append(" ").append(v.getSimpleName()); sep = ", "; } - + w.append(") {\n"); - w.append(" return Builder.newDialog(\"").append(url).append("\").\n"); - generateTechIds(w, techIds); - w.append(" loadFinished(new Runnable() {\n"); + w.append(" class DialogImpl implements Runnable"); + if (returnsOnSubmit) { + w.append(", org.netbeans.api.htmlui.HTMLDialog.OnSubmit {\n"); + w.append(" private volatile org.netbeans.api.htmlui.HTMLDialog.OnSubmit delegate;\n"); + w.append("\n"); + w.append(" @Override\n"); + w.append(" public boolean onSubmit(String id) {\n"); + w.append(" return delegate == null || delegate.onSubmit(id);\n"); + w.append(" }\n"); + } else { + w.append(" {\n"); + } + w.append(" @Override\n"); w.append(" public void run() {\n"); - w.append(" ").append(ee.getEnclosingElement().getSimpleName()) + w.append(" "); + if (returnsOnSubmit) { + w.append("delegate = "); + } + w.append(ee.getEnclosingElement().getSimpleName()) .append(".").append(ee.getSimpleName()).append("("); sep = ""; for (VariableElement v : ee.getParameters()) { @@ -241,11 +266,24 @@ private void generateDialog(Writer w, ExecutableElement ee, String url, String[] } w.append(");\n"); w.append(" }\n"); - w.append(" }).\n"); - w.append(" showAndWait();\n"); + w.append(" }\n"); + w.append(" DialogImpl impl = new DialogImpl();\n"); + if (returnsOnSubmit) { + w.append(" "); + } else { + w.append(" return "); + } + w.append("Builder.newDialog(\"").append(url).append("\").\n"); + generateTechIds(w, techIds); + w.append(" loadFinished(impl).\n"); + if (returnsOnSubmit) { + w.append(" show(impl);\n"); + } else { + w.append(" showAndWait();\n"); + } w.append(" }\n"); } - + private void generateComponent( Writer w, ExecutableElement ee, String type, String url, String[] techIds ) throws IOException { @@ -257,7 +295,7 @@ private void generateComponent( w.append("final ").append(v.asType().toString()).append(" ").append(v.getSimpleName()); sep = ", "; } - + w.append(") {\n"); w.append(" return Builder.newDialog(\"").append(url).append("\").\n"); generateTechIds(w, techIds); @@ -281,14 +319,14 @@ private void generateComponent( private void error(final String msg, Element e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e); } - + private static PackageElement findPkg(Element e) { while (e.getKind() != ElementKind.PACKAGE) { e = e.getEnclosingElement(); } return (PackageElement)e; } - + private String[] splitPkg(String s, Element e) { int last = s.lastIndexOf('.'); if (last == -1) { @@ -323,7 +361,7 @@ public int compare(ExecutableElement o1, ExecutableElement o2) { } return id1 - id2; } - + FileObject validateResource(String resource, Element originatingElement, Annotation annotation, String annotationMethod, boolean searchClasspath) throws LayerGenerationException { if (resource.startsWith("/")) { throw new LayerGenerationException("do not use leading slashes on resource paths", originatingElement, processingEnv, annotation, annotationMethod); diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java index a535d710e2de..dfdcac664e12 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogView.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.function.Consumer; import net.java.html.js.JavaScriptBody; +import org.netbeans.api.htmlui.HTMLDialog; import org.openide.util.Exceptions; final class HTMLDialogView extends HTMLDialogBase { @@ -35,20 +36,31 @@ public HTMLDialogView(String url, HtmlPair<?> view) { this.buttons = new FooterButtons(); } + @Override + public void show(HTMLDialog.OnSubmit onSubmit) { + buttons.onSubmit = onSubmit; + makeVisible(onSubmit); + } + + @Override public String showAndWait() { + makeVisible(null); + return this.buttons.obtainResult(); + } + + private void makeVisible(HTMLDialog.OnSubmit onSubmit) { view.makeVisible(() -> { try { view.load(getClass().getClassLoader(), new URL(url), () -> { onPageLoad.run(); List<Object> b = buttons.buttons(); - return null; + return onSubmit; }, this.techIds.toArray(new String[0])); } catch (MalformedURLException ex) { Exceptions.printStackTrace(ex); } }); - return this.buttons.obtainResult(); } @Override @@ -60,12 +72,13 @@ public <C> C component(Class<C> type) { protected void onSubmit(String id) { this.buttons.accept(id); } - + private final class FooterButtons extends Buttons<Object> implements Consumer<String> { private static final String PREFIX = "dialog-buttons-"; private boolean hasResult; private String result; - + private HTMLDialog.OnSubmit onSubmit; + public synchronized String obtainResult() { while (!hasResult) { try { @@ -85,13 +98,19 @@ public synchronized void accept(String t) { if (t == null) { result = null; } else if (t.startsWith(PREFIX)) { - result = t.substring(PREFIX.length()); + String r = t.substring(PREFIX.length()); + if (onSubmit != null && !onSubmit.onSubmit(r)) { + return; + } + result = r; } + + hasResult = true; notifyAll(); closeWindow0(); } - + @Override protected Object createButton(String name) { return view.createButton(PREFIX + name, this); @@ -121,7 +140,7 @@ protected void runLater(Runnable r) { r.run(); } } - + @JavaScriptBody(args = { "b" }, body = "return b.id;") native static String buttonName0(Object b); diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogOnSubmitTest.java b/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogOnSubmitTest.java new file mode 100644 index 000000000000..bbbfb85a0283 --- /dev/null +++ b/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/DialogOnSubmitTest.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.htmlui; + +import java.net.URL; +import java.net.URLStreamHandlerFactory; +import java.util.concurrent.CountDownLatch; +import net.java.html.json.Model; +import net.java.html.json.Property; +import org.netbeans.api.htmlui.HTMLDialog; +import org.netbeans.api.htmlui.HTMLDialog.OnSubmit; +import org.netbeans.html.boot.spi.Fn; +import org.netbeans.junit.MockServices; +import org.openide.util.Lookup; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import org.testng.annotations.Test; + +public class DialogOnSubmitTest { + static { + URLStreamHandlerFactory f = Lookup.getDefault().lookup(URLStreamHandlerFactory.class); + assertNotNull(f, "Factory found"); + URL.setURLStreamHandlerFactory(f); + } + + @HTMLDialog(url = "simple.html", className = "DialogOnSubmitTestPages") + static OnSubmit askQuestion( + boolean yes, Fn.Presenter[] presenter, String[] usedButton, + CountDownLatch loaded, CountDownLatch clicked + ) { + presenter[0] = Fn.activePresenter(); + loaded.countDown(); + return (id) -> { + usedButton[0] = id; + clicked.countDown(); + return true; + }; + } + + @Test + public void callbackDialog() throws Exception { + MockServices.setServices(MockHtmlViewer.class); + + String[] usedButton = { null }; + Fn.Presenter[] presenter = { null }; + CountDownLatch loaded = new CountDownLatch(1); + CountDownLatch clicked = new CountDownLatch(1); + DialogOnSubmitTestPages.askQuestion(true, presenter, usedButton, loaded, clicked); + loaded.await(); + assertNotNull(presenter[0], "Presenter found"); + MockHtmlViewer.selectButton(presenter[0], "MockOK"); + clicked.await(); + assertEquals(usedButton[0], "MockOK"); + } +} diff --git a/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/MockHtmlViewer.java b/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/MockHtmlViewer.java new file mode 100644 index 000000000000..f8e352b8638d --- /dev/null +++ b/platform/api.htmlui/test/unit/src/org/netbeans/modules/htmlui/MockHtmlViewer.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.htmlui; + +import java.io.Closeable; +import java.io.Reader; +import java.net.URL; +import java.util.concurrent.Callable; +import java.util.function.Consumer; +import org.netbeans.api.htmlui.HTMLDialog; +import org.netbeans.html.boot.spi.Fn; +import org.netbeans.spi.htmlui.HtmlViewer; + +public final class MockHtmlViewer implements HtmlViewer<MockHtmlViewer.MockUI> { + @Override + public MockUI newView(Consumer<String> lifeCycleCallback) { + return new MockUI(); + } + + @Override + public void makeVisible(MockUI view, Runnable whenReady) { + whenReady.run(); + } + + @Override + public void load(MockUI view, ClassLoader loader, URL pageUrl, Callable<Object> initialize, String[] techIds) { + try (Closeable c = Fn.activate(view)) { + view.onSubmit = initialize.call(); + } catch (Exception ex) { + throw new AssertionError(ex); + } + } + + @Override + public Object createButton(MockUI view, String id) { + return new MockButton(); + } + + static void selectButton(Fn.Presenter p, String id) { + MockUI ui = (MockUI) p; + if (ui.onSubmit instanceof HTMLDialog.OnSubmit) { + ((HTMLDialog.OnSubmit) ui.onSubmit).onSubmit(id); + } + } + + public static final class MockButton { + } + + static final class MockUI implements Fn.Presenter { + private Object onSubmit; + + @Override + public Fn defineFn(String fn, String... strings) { + return new MockFn(fn); + } + + @Override + public void displayPage(URL url, Runnable r) { + throw new UnsupportedOperationException(); + } + + @Override + public void loadScript(Reader reader) throws Exception { + throw new UnsupportedOperationException(); + } + + } + + private static class MockFn extends Fn { + private final String fn; + + MockFn(String fn) { + this.fn = fn; + } + + @Override + public Object invoke(Object o, Object... os) throws Exception { + if (fn.contains("getElementsByTagName('button')")) { + return new Object[0]; + } + return null; + } + } +} diff --git a/platform/htmlui/nbproject/project.xml b/platform/htmlui/nbproject/project.xml index d261200230f5..220b288b114e 100644 --- a/platform/htmlui/nbproject/project.xml +++ b/platform/htmlui/nbproject/project.xml @@ -10,7 +10,7 @@ <build-prerequisite/> <compile-dependency/> <run-dependency> - <specification-version>1.21</specification-version> + <specification-version>1.23</specification-version> </run-dependency> </dependency> <dependency> From 2e15163a0d5f8e24f3d1ee60a7132cef13dc079d Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Mon, 6 Dec 2021 13:17:53 +0100 Subject: [PATCH 26/38] Replace the state machine by chain of Runnables --- .../modules/htmlui/HTMLDialogImpl.java | 112 +++++++----------- 1 file changed, 40 insertions(+), 72 deletions(-) diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java index 607359b1c816..2b6dbfba8cdd 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java @@ -33,67 +33,52 @@ import org.openide.util.Exceptions; import org.openide.util.Lookup; -final class HTMLDialogImpl extends HTMLDialogBase implements Runnable { - private volatile int state; +final class HTMLDialogImpl extends HTMLDialogBase { private final ChromeWithButtons panel; - private Object webView; - private boolean nestedLoop; HTMLDialogImpl(String url) { super(url); this.panel = new ChromeWithButtons(); } - @Override - public void run() { - switch (state) { - case 0: - initPanel(); - break; - case 1: - state = 2; - webView = HtmlToolkit.getDefault().initHtmlDialog(url, panel.dd, panel.p, this, techIds); - break; - case 2: - initPage(); - if (nestedLoop) { - state = 3; - EventQueue.invokeLater(this); - } else { - state = -1; - } - break; - case 3: - showDialog(); - state = 4; - HtmlToolkit.getDefault().execute(this); - break; - case 4: - state = -1; + final Runnable initializationSequence(Runnable afterInitPage) { + return () -> { + HtmlToolkit.getDefault().execute(() -> { + HtmlToolkit.getDefault().initHtmlDialog(url, panel.dd, panel.p, () -> { + initPage(); + if (afterInitPage != null) { + EventQueue.invokeLater(afterInitPage); + } + }, techIds); + }); + }; + } + + final Runnable initializationNestedLoop() { + return initializationSequence(() -> { + panel.showDialog(null); + HtmlToolkit.getDefault().execute(() -> { HtmlToolkit.getDefault().exitNestedLoop(this); - break; - default: - throw new IllegalStateException("State: " + state); - } + }); + }); } @Override public String showAndWait() { if (EventQueue.isDispatchThread()) { - run(); - showDialog(); + initializationSequence(null).run(); + panel.showDialog(null); } else { if (HtmlToolkit.getDefault().isApplicationThread()) { - nestedLoop = true; - EventQueue.invokeLater(this); + EventQueue.invokeLater(initializationNestedLoop()); HtmlToolkit.getDefault().enterNestedLoop(this); } else { try { - EventQueue.invokeAndWait(this); + EventQueue.invokeAndWait(initializationSequence(null)); } catch (InterruptedException | InvocationTargetException ex) { throw new IllegalStateException(ex); } - showDialog(); + panel.showDialog(null); } } return panel.getValueName(); @@ -101,39 +86,15 @@ public String showAndWait() { @Override public void show(HTMLDialog.OnSubmit onSubmit) { - if (EventQueue.isDispatchThread()) { - run(); - showDialog(); - } else { - if (HtmlToolkit.getDefault().isApplicationThread()) { - nestedLoop = true; - EventQueue.invokeLater(this); - HtmlToolkit.getDefault().enterNestedLoop(this); - } else { - try { - EventQueue.invokeAndWait(this); - } catch (InterruptedException | InvocationTargetException ex) { - throw new IllegalStateException(ex); - } - showDialog(); - } - } - panel.getValueName(); + EventQueue.invokeLater(initializationSequence(() -> { + panel.showDialog(onSubmit); + })); } @Override protected void onSubmit(String id) { } - private void showDialog() { - panel.showDialog(); - } - - private void initPanel() { - state = 1; - HtmlToolkit.getDefault().execute(this); - } - private void initPage() { try { onPageLoad.run(); @@ -145,7 +106,6 @@ private void initPage() { @Override public <C> C component(Class<C> type) { - state = -1; ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class); if (loader == null) { loader = HTMLDialogImpl.class.getClassLoader(); @@ -158,7 +118,7 @@ public <C> C component(Class<C> type) { } return HtmlToolkit.getDefault().convertToComponent(type, pageUrl, loader, onPageLoad, techIds); } - + private static final class ChromeWithButtons extends Buttons<JButton> { final JComponent p; final DialogDescriptor dd; @@ -168,8 +128,6 @@ public ChromeWithButtons() { this.dd = new DialogDescriptor(p, ""); this.dd.setOptions(new Object[0]); } - - @Override protected JButton createButton(String name) { @@ -203,15 +161,25 @@ String getValueName() { return val instanceof JButton ? ((JButton)val).getName() : null; } - void showDialog() { + void showDialog(HTMLDialog.OnSubmit onSubmit) { p.setPreferredSize(new Dimension(600, 400)); Dialog d = DialogDisplayer.getDefault().createDialog(dd); + dd.setButtonListener((ev) -> { + if (onSubmit != null && ev.getSource() instanceof JButton) { + JButton src = (JButton) ev.getSource(); + if (!onSubmit.onSubmit(src.getName())) { + return; + } + } + d.setVisible(false); + }); d.setVisible(true); } void initButtons() { List<JButton> buttons = buttons(); dd.setOptions(buttons.toArray(new JButton[0])); + dd.setClosingOptions(new Object[0]); } } } From 7f2c85c4579d0976107fb0947584438287d62a25 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach <jaroslav.tulach@oracle.com> Date: Mon, 6 Dec 2021 15:27:59 +0100 Subject: [PATCH 27/38] Keeping just HtmlViewer in the SPI of htmlui module --- ...angeMethodParametersRefactoringAction.java | 1 - .../lsp/server/refactoring/ui/TestHtmlUI.html | 25 ++ .../refactoring/ui/TestHtmlUICntrl.java | 90 +++++++ .../lsp/server/ui/AbstractLspHtmlViewer.java | 40 ++- .../org/netbeans/api/htmlui/HTMLDialog.java | 1 - .../org/netbeans/modules/htmlui/Buttons.java | 100 +++++-- .../modules/htmlui/HTMLDialogBase.java | 4 +- .../modules/htmlui/HTMLDialogImpl.java | 185 ------------- .../modules/htmlui/HTMLDialogView.java | 96 +------ .../org/netbeans/modules/htmlui/HtmlPair.java | 37 ++- .../org/netbeans/modules/htmlui/Pages.java | 16 +- .../org/netbeans/spi/htmlui/HtmlViewer.java | 16 +- .../modules/htmlui/MockHtmlViewer.java | 28 +- platform/htmlui/nbproject/project.xml | 32 ++- .../modules/htmlui/DefaultHtmlToolkit.java | 3 +- .../modules/htmlui/HtmlComponent.java | 71 ++--- .../netbeans/modules}/htmlui/HtmlToolkit.java | 5 +- .../modules/htmlui/SwingFXViewer.java | 245 ++++++++++++++++++ .../modules/htmlui/jfx/JavaFxHtmlToolkit.java | 2 +- .../netbeans/modules/htmlui/DialogsTest.java | 35 +-- .../modules/htmlui/HtmlComponentTest.java | 24 +- 21 files changed, 623 insertions(+), 433 deletions(-) create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/TestHtmlUI.html create mode 100644 java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/TestHtmlUICntrl.java delete mode 100644 platform/api.htmlui/src/org/netbeans/modules/htmlui/HTMLDialogImpl.java rename platform/{api.htmlui => htmlui}/src/org/netbeans/modules/htmlui/DefaultHtmlToolkit.java (96%) rename platform/{api.htmlui => htmlui}/src/org/netbeans/modules/htmlui/HtmlComponent.java (75%) rename platform/{api.htmlui/src/org/netbeans/spi => htmlui/src/org/netbeans/modules}/htmlui/HtmlToolkit.java (93%) create mode 100644 platform/htmlui/src/org/netbeans/modules/htmlui/SwingFXViewer.java diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java index 82b65358a005..a01e58c050f9 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoringAction.java @@ -24,7 +24,6 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; import org.netbeans.api.java.source.ElementHandle; import org.netbeans.api.java.source.JavaSource; import org.openide.awt.ActionID; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/TestHtmlUI.html b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/TestHtmlUI.html new file mode 100644 index 000000000000..e70b8863734b --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/TestHtmlUI.html @@ -0,0 +1,25 @@ +<html> + <head> + <title>TestHtmlUI + + + +
+ + + + + + + + \ No newline at end of file diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/TestHtmlUICntrl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/TestHtmlUICntrl.java new file mode 100644 index 000000000000..c33fb93b9068 --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/TestHtmlUICntrl.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.java.lsp.server.refactoring.ui; + +import net.java.html.json.Model; +import net.java.html.json.Function; +import net.java.html.json.Property; +import net.java.html.json.ComputedProperty; +import org.netbeans.api.htmlui.OpenHTMLRegistration; +import org.netbeans.api.htmlui.HTMLDialog; +import org.openide.util.NbBundle; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; + +/** + * HTML page which displays a window and also a dialog. + */ +@Model(className = "TestHtmlUI", targetId = "", properties = { + @Property(name = "text", type = String.class) +}) +public final class TestHtmlUICntrl { + + @ComputedProperty + static String templateName() { + return "window"; + } + + @Function + static void showDialog(TestHtmlUI model) { + String reply = Pages.showTestHtmlUIDialog(model.getText()); + if ("OK".equals(reply)) { + model.setText("Happy World!"); + } else { + model.setText("Sad World!"); + } + } + + @ActionID( + category = "Tools", + id = "org.netbeans.modules.java.lsp.server.refactoring.ui.TestHtmlUI" + ) + @ActionReferences({ + @ActionReference(path = "Menu/Refactoring", position = 1125) + }) + @NbBundle.Messages("CTL_TestHtmlUI=Open HTML Hello World!") + @OpenHTMLRegistration( + url = "TestHtmlUI.html", + displayName = "#CTL_TestHtmlUI" + //, iconBase="SET/PATH/TO/ICON/HERE" + ) + public static TestHtmlUI onPageLoad() { + return new TestHtmlUI("Hello World!").applyBindings(); + } + + // + // dialog UI + // + @HTMLDialog(url = "TestHtmlUI.html") + static void showTestHtmlUIDialog(String t) { + new TestHtmlUIDialog(t, false).applyBindings(); + } + + @Model(className = "TestHtmlUIDialog", targetId = "", properties = { + @Property(name = "text", type = String.class), + @Property(name = "ok", type = boolean.class),}) + static final class DialogCntrl { + + @ComputedProperty + static String templateName() { + return "dialog"; + } + } +} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java index ba456ea80a81..e6455c0b32cc 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java @@ -20,14 +20,16 @@ import java.net.URL; import java.util.concurrent.Callable; +import java.util.concurrent.Executor; import java.util.function.Consumer; import net.java.html.js.JavaScriptBody; +import org.netbeans.api.htmlui.HTMLDialog.OnSubmit; import org.netbeans.modules.java.lsp.server.htmlui.Browser; import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams; import org.netbeans.spi.htmlui.HtmlViewer; import org.openide.util.Exceptions; -public class AbstractLspHtmlViewer implements HtmlViewer { +public class AbstractLspHtmlViewer implements HtmlViewer { protected AbstractLspHtmlViewer() { } @@ -38,7 +40,7 @@ public View newView(Consumer lifeCycleCallback) { } @Override - public void makeVisible(View view, Runnable whenReady) { + public void makeVisible(View view, OnSubmit submit, Runnable whenReady) { whenReady.run(); } @@ -88,6 +90,40 @@ public Object createButton(View view, String id) { ) native static Object createButton0(String id, Consumer callback); + @Override + public C component(View view, Class type, String url, ClassLoader classLoader, Runnable onPageLoad, String[] techIds) { + throw new ClassCastException(view + " cannot be cast to " + type); + } + + @Override + public String getName(View view, Object b) { + return buttonName0(b); + } + + @Override + public void setText(View view, Object b, String text) { + buttonText0(b, text); + } + + @Override + public void setEnabled(View view, Object b, boolean enabled) { + buttonDisabled0(b, !enabled); + } + + @Override + public void runLater(View view, Runnable r) { + r.run(); + } + + @JavaScriptBody(args = { "b" }, body = "return b.id;") + native static String buttonName0(Object b); + + @JavaScriptBody(args = { "b", "text" }, body = "b.innerHTML = text;") + native static void buttonText0(Object b, String text); + + @JavaScriptBody(args = { "b", "disabled" }, body = "return b.disabled = disabled;") + native static String buttonDisabled0(Object b, boolean disabled); + static final class View { private final Consumer callback; private final UIContext ui; diff --git a/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java b/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java index f016bbf8c37e..3f256c1d0530 100644 --- a/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java +++ b/platform/api.htmlui/src/org/netbeans/api/htmlui/HTMLDialog.java @@ -24,7 +24,6 @@ import java.lang.annotation.Target; import java.util.Locale; import java.awt.event.ActionEvent; -import java.util.concurrent.Callable; import net.java.html.json.Model; import net.java.html.json.Property; import org.netbeans.html.context.spi.Contexts.Id; diff --git a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java index 6fea85dba511..025ac4b5659e 100644 --- a/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java +++ b/platform/api.htmlui/src/org/netbeans/modules/htmlui/Buttons.java @@ -23,22 +23,40 @@ import java.util.List; import java.util.Objects; import net.java.html.js.JavaScriptBody; +import org.netbeans.api.htmlui.HTMLDialog; +import org.netbeans.spi.htmlui.HtmlViewer; import org.openide.util.NbBundle; /** * * @author Jaroslav Tulach */ -abstract class Buttons